home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / bin / ckbcomp < prev    next >
Text File  |  2008-08-27  |  111KB  |  3,790 lines

  1. #!/usr/bin/perl
  2.  
  3. #     ckbcomp -- compile XKB keyboard definitions to loadkeys format
  4. #     Copyright ┬⌐ 2005,2006 Anton Zinoviev <anton@lml.bas.bg>
  5.  
  6. #     This program is free software; you can redistribute it and/or modify
  7. #     it under the terms of the GNU General Public License as published by
  8. #     the Free Software Foundation; either version 2 of the License, or
  9. #     (at your option) any later version.
  10.  
  11. #     This program is distributed in the hope that it will be useful,
  12. #     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. #     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. #     GNU General Public License for more details.
  15.  
  16. #     If you have not received a copy of the GNU General Public License
  17. #     along with this program, write to the Free Software Foundation, Inc.,
  18. #     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  
  20. use warnings 'all';
  21. use strict;
  22.  
  23. my $debug_flag = 1;
  24. sub debug {
  25.     if ($debug_flag) {
  26.     print STDERR "@_";
  27.     }
  28. }
  29.  
  30. sub warning {
  31.     print STDERR  "WARNING: @_";
  32. }
  33.  
  34. ########### ARGUMENTS ###############################################
  35.  
  36. my $charmap;
  37. my $acm;
  38.  
  39. my $verbosity = 0;
  40.  
  41. my @xdirs = ('/etc/console-setup/ckb',
  42.          '/usr/share/X11/xkb',
  43.          '/etc/X11/xkb',
  44.          '/usr/X11R6/lib/X11/xkb');
  45.  
  46. my $keycodes;
  47. my $symbols;
  48.  
  49. my $rules;
  50. my $model;
  51. my @layouts;
  52. my @variants = ();
  53. my @options = ();
  54. my $compact = 0;
  55.  
  56. while (@ARGV) {
  57.     $_ = shift @ARGV;
  58.     if (s/^-//) {
  59.     if (/^charmap$/) {
  60.         if ($charmap) {
  61.         die "$0: No more than one -charmap option is allowed\n";
  62.         }
  63.         $charmap = $ARGV[0];
  64.         shift @ARGV;
  65.     } elsif (/^v(erbose)?$/) {
  66.         if ($verbosity) {
  67.         die "$0: No more than one -verbose option is allowed\n";
  68.         }
  69.         if ($ARGV[0] =~ /^[0-9]|10$/) {
  70.         $verbosity = $ARGV[0];
  71.         shift @ARGV;
  72.         } else {
  73.         $verbosity = 5;
  74.         }
  75.     } elsif (/^I(.*)$/) {
  76.         @xdirs = ($1, @xdirs);
  77.     } elsif (/^keycodes$/) {
  78.         if ($keycodes) {
  79.         die "$0: No more than one -keycodes option is allowed\n";
  80.         }
  81.         $keycodes = $ARGV[0];
  82.         shift @ARGV;
  83.     } elsif (/^symbols$/) {
  84.         if ($symbols) {
  85.         die "$0: No more than one -symbols option is allowed\n";
  86.         }
  87.         $symbols = $ARGV[0];
  88.         shift @ARGV;
  89.     } elsif (/^rules$/) {
  90.         if ($rules) {
  91.         die "$0: No more than one -rules option is allowed\n";
  92.         }
  93.         $rules = $ARGV[0];
  94.         shift @ARGV;
  95.     } elsif (/^model$/) {
  96.         if ($model) {
  97.         die "$0: No more than one -model option is allowed\n";
  98.         }
  99.         $model = $ARGV[0];
  100.         shift @ARGV;
  101.     } elsif (/^layout$/) {
  102.         if (@layouts) {
  103.         die "$0: No more than one -layout option is allowed\n";
  104.         }
  105.         @layouts = split (/,/, $ARGV[0], -1);
  106.         shift @ARGV;
  107.     } elsif (/^variant$/) {
  108.         if (@variants) {
  109.         die "$0: No more than one -variant option is allowed\n";
  110.         }
  111.         @variants = split (/,/, $ARGV[0], -1);
  112.         shift @ARGV;
  113.     } elsif (/^option$/) {
  114.         @options = (@options, split (/,/, $ARGV[0], -1));
  115.         shift @ARGV;
  116.     } elsif (/^help$|^-help$|^\?$/) {
  117.         print <<EOT;
  118. Usage: ckbcomp [args] [<layout> [<variant> [<option> ... ]]]
  119. Where legal args are:
  120. -?,-help            Print this message
  121. -charmap <name>     Specifies the encoding to use
  122. -I<dir>             Add <dir> to list of directories to be used
  123. -keycodes <name>    Specifies keycodes component name
  124. -symbols <name>     Specifies symbols component name
  125. -rules <name>       Name of rules file to use
  126. -model <name>       Specifies model used to choose component names
  127. -layout <name>      Specifies layout used to choose component names
  128. -variant <name>     Specifies layout variant used to choose component names
  129. -option <name>      Adds an option used to choose component names
  130. -v[erbose] [<lvl>]  Sets verbosity (1..10).  Higher values yield
  131.                     more messages
  132. -compact            Generate compact keymap
  133. EOT
  134.             exit 0;
  135.     } elsif (/^compact$/) {
  136.         $compact = 1;
  137.     } else {
  138.         die "$0: Unknown option -$_\n";
  139.     }
  140.     } else {
  141.     if (! @layouts) {
  142.         @layouts = split (/,/, $_, -1);
  143.     } elsif (! @variants) {
  144.         @variants = split (/,/, $_, -1);
  145.         @variants = ('') if (! @variants);
  146.     } else {
  147.         @options = (@options, split (/,/, $_, -1));
  148.     }
  149.     }
  150. }
  151.  
  152. $rules = 'xorg' if (! $rules);
  153. $model = 'pc104' if (! $model);
  154.  
  155. ########### GLOBAL VARIABLES #########################################
  156.  
  157. my %rules_variables = (); # The variables defined in the rules file
  158.  
  159. my $arch = 'at'; # The name of a mapping between X key codes and kernel
  160.                  # keycodes
  161.  
  162. my %acmtable; # Unicode -> legacy code (defined only when -charmap is given)
  163.  
  164. my %keycodes_table; # x keysym -> x key code
  165. my %aliases;        # x keysym -> x keysym
  166.  
  167. my %symbols_table;   # x key code -> [[symbols for group0,...],
  168.                      #                [symbols for group1,...], ...]
  169. my %types_table;     # x key code -> key type (i.e. "TWO_LEVEL")
  170.  
  171. my $augment_method = 1;   # Constants for different XKB include methods
  172. my $override_method = 2;
  173. my $replace_method = 3;
  174. my $alternate_method = 4;
  175. my $ignore_method = 5;    # This is not a XKB method and means "don't include"
  176.  
  177. my $filename;       # The name of the currently read file
  178. my $stream = '';    # The contents of $filename that still has not been parsed
  179. my $method = $override_method; # The current method (by default "override")
  180. my $base_group = 0; # The base group to include in (for "symbols" files only)
  181.  
  182. my %kernel_modifiers = ('Shift' => 0x01,
  183.             'Shift_Lock' => 0x01,
  184.             'AltGr' => 0x02,
  185.             'AltGr_Lock' => 0x02,
  186.             'Control' => 0x04,
  187.             'Control_Lock' => 0x04,
  188.             'Alt' => 0x08,
  189.             'Alt_Lock' => 0x08,
  190.             'ShiftL' => 0x10,
  191.             'ShiftL_Lock' => 0x10,
  192.             'ShiftR' => 0x20,
  193.             'ShiftR_Lock' => 0x20);
  194.  
  195. my @modifier_combinations = ('plain',
  196.                              'shift',
  197.                              'altgr',
  198.                              'altgr shift',
  199.                              'control',
  200.                              'control shift',
  201.                              'control altgr',
  202.                              'control altgr shift',
  203.                              'alt',
  204.                              'alt shift',
  205.                              'alt altgr',
  206.                              'alt altgr shift',
  207.                              'alt control',
  208.                              'alt control shift',
  209.                              'alt control altgr',
  210.                              'alt control altgr shift',
  211.                              'shiftl',
  212.                              'shiftl shift',
  213.                              'shiftl altgr',
  214.                              'shiftl altgr shift',
  215.                              'shiftl control',
  216.                              'shiftl control shift',
  217.                              'shiftl control altgr',
  218.                              'shiftl control altgr shift',
  219.                              'shiftl alt',
  220.                              'shiftl alt shift',
  221.                              'shiftl alt altgr',
  222.                              'shiftl alt altgr shift',
  223.                              'shiftl alt control',
  224.                              'shiftl alt control shift',
  225.                              'shiftl alt control altgr',
  226.                              'shiftl alt control altgr shift',
  227.                              'shiftr',
  228.                              'shiftr shift',
  229.                              'shiftr altgr',
  230.                              'shiftr altgr shift',
  231.                              'shiftr control',
  232.                              'shiftr control shift',
  233.                              'shiftr control altgr',
  234.                              'shiftr control altgr shift',
  235.                              'shiftr alt',
  236.                              'shiftr alt shift',
  237.                              'shiftr alt altgr',
  238.                              'shiftr alt altgr shift',
  239.                              'shiftr alt control',
  240.                              'shiftr alt control shift',
  241.                              'shiftr alt control altgr',
  242.                              'shiftr alt control altgr shift',
  243.                              'shiftr shiftl',
  244.                              'shiftr shiftl shift',
  245.                              'shiftr shiftl altgr',
  246.                              'shiftr shiftl altgr shift',
  247.                              'shiftr shiftl control',
  248.                              'shiftr shiftl control shift',
  249.                              'shiftr shiftl control altgr',
  250.                              'shiftr shiftl control altgr shift',
  251.                              'shiftr shiftl alt',
  252.                              'shiftr shiftl alt shift',
  253.                              'shiftr shiftl alt altgr',
  254.                              'shiftr shiftl alt altgr shift',
  255.                              'shiftr shiftl alt control',
  256.                              'shiftr shiftl alt control shift',
  257.                              'shiftr shiftl alt control altgr',
  258.                              'shiftr shiftl alt control altgr shift',
  259.                 );
  260.  
  261. # Some Unicodes cause the kernel/loadkeys to issue "Segmentation fault"
  262. my %forbidden;
  263. {
  264.     for my $i (0xfd00..0xfdff) {
  265.     $forbidden{$i} = 1;
  266.     }
  267. }
  268.  
  269. my %xkbsym_table = (
  270. # Control symbols
  271.     'BackSpace' => 'Delete',  # 0008
  272.     'Tab' => 'Tab',           # 0009
  273.     'Linefeed' => 'Linefeed', # 000a
  274.     'Return' => 'Return',     # 000d
  275.     'Escape' => 'Escape',     # 001b
  276. # Alphanumeric symbols
  277.     'space' => '0020',
  278.     'exclam' => '0021',
  279.     'quotedbl' => '0022',
  280.     'numbersign' => '0023',
  281.     'dollar' => '0024',
  282.     'percent' => '0025',
  283.     'ampersand' => '0026',
  284.     'apostrophe' => '0027',
  285.     'quoteright' => '0027',
  286.     'parenleft' => '0028',
  287.     'parenlef' => '0028', # Is this recognised by X ? (speling error)
  288.     'parenright' => '0029',
  289.     'asterisk' => '002a',
  290.     'asterix' => '002a', # Is this recognised by X ? (speling error)
  291.     'plus' => '002b',
  292.     'comma' => '002c',
  293.     'minus' => '002d',
  294.     'period' => '002e',
  295.     'slash' => '002f',
  296.     '0' => '0030',
  297.     '1' => '0031',
  298.     '2' => '0032',
  299.     '3' => '0033',
  300.     '4' => '0034',
  301.     '5' => '0035',
  302.     '6' => '0036',
  303.     '7' => '0037',
  304.     '8' => '0038',
  305.     '9' => '0039',
  306.     'colon' => '003a',
  307.     'semicolon' => '003b',
  308.     'less' => '003c',
  309.     'equal' => '003d',
  310.     'greater' => '003e',
  311.     'question' => '003f',
  312.     'at' => '0040',
  313.     'A' => '0041',
  314.     'B' => '0042',
  315.     'C' => '0043',
  316.     'D' => '0044',
  317.     'E' => '0045',
  318.     'F' => '0046',
  319.     'G' => '0047',
  320.     'H' => '0048',
  321.     'I' => '0049',
  322.     'J' => '004a',
  323.     'K' => '004b',
  324.     'L' => '004c',
  325.     'M' => '004d',
  326.     'N' => '004e',
  327.     'O' => '004f',
  328.     'P' => '0050',
  329.     'Q' => '0051',
  330.     'R' => '0052',
  331.     'S' => '0053',
  332.     'T' => '0054',
  333.     'U' => '0055',
  334.     'V' => '0056',
  335.     'W' => '0057',
  336.     'X' => '0058',
  337.     'Y' => '0059',
  338.     'Z' => '005a',
  339.     'bracketleft' => '005b',
  340.     'backslash' => '005c',
  341.     'backlash' => '005c',   # Is this recognised by X ? (speling error)
  342.     'bracketright' => '005d',
  343.     'circumflex' => '005e',
  344.     'asciicircum' => '005e',
  345.     'underscore' => '005f',
  346.     'grave' => '0060',
  347.     'quoteleft' => '0060',
  348.     'a' => '0061',
  349.     'b' => '0062',
  350.     'c' => '0063',
  351.     'd' => '0064',
  352.     'e' => '0065',
  353.     'f' => '0066',
  354.     'g' => '0067',
  355.     'h' => '0068',
  356.     'i' => '0069',
  357.     'j' => '006a',
  358.     'k' => '006b',
  359.     'l' => '006c',
  360.     'm' => '006d',
  361.     'n' => '006e',
  362.     'o' => '006f',
  363.     'p' => '0070',
  364.     'q' => '0071',
  365.     'r' => '0072',
  366.     's' => '0073',
  367.     't' => '0074',
  368.     'u' => '0075',
  369.     'v' => '0076',
  370.     'w' => '0077',
  371.     'x' => '0078',
  372.     'y' => '0079',
  373.     'z' => '007a',
  374.     'braceleft' => '007b',
  375.     'pipe' => '007c', # Is this recognised by X ?
  376.     'bar' => '007c',
  377.     'braceright' => '007d',
  378.     'asciitilde' => '007e',
  379.     'nobreakspace' => '00a0',
  380.     'exclamdown' => '00a1',
  381.     'cent' => '00a2',
  382.     'sterling' => '00a3',
  383.     'currency' => '00a4',
  384.     'yen' => '00a5',
  385.     'brokenbar' => '00a6',
  386.     'section' => '00a7',
  387.     'diaeresis' => '00a8',
  388.     'copyright' => '00a9',
  389.     'ordfeminine' => '00aa',
  390.     'guillemotleft' => '00ab',
  391.     'notsign' => '00ac',
  392.     'hyphen' => '00ad',
  393.     'registered' => '00ae',
  394.     'macron' => '00af',
  395.     'overbar' => '00af',
  396.     'degree' => '00b0',
  397.     'plusminus' => '00b1',
  398.     'twosuperior' => '00b2',
  399.     'threesuperior' => '00b3',
  400.     'acute' => '0027', # APOSTROPHE instead of ACUTE ACCENT
  401.     'mu' => '00b5',
  402.     'paragraph' => '00b6',
  403.     'periodcentered' => '00b7',
  404.     'cedilla' => '00b8',
  405.     'onesuperior' => '00b9',
  406.     'masculine' => '00ba',
  407.     'guillemotright' => '00bb',
  408.     'onequarter' => '00bc',
  409.     'onehalf' => '00bd',
  410.     'threequarters' => '00be',
  411.     'questiondown' => '00bf',
  412.     'Agrave' => '00c0',
  413.     'Aacute' => '00c1',
  414.     'Acircumflex' => '00c2',
  415.     'Atilde' => '00c3',
  416.     'Adiaeresis' => '00c4',
  417.     'Aring' => '00c5',
  418.     'AE' => '00c6',
  419.     'Ccedilla' => '00c7',
  420.     'Egrave' => '00c8',
  421.     'Eacute' => '00c9',
  422.     'Ecircumflex' => '00ca',
  423.     'Ediaeresis' => '00cb',
  424.     'Igrave' => '00cc',
  425.     'Iacute' => '00cd',
  426.     'Icircumflex' => '00ce',
  427.     'Idiaeresis' => '00cf',
  428.     'ETH' => '00d0',
  429.     'Eth' => '00d0',
  430.     'Ntilde' => '00d1',
  431.     'Ograve' => '00d2',
  432.     'Oacute' => '00d3',
  433.     'Ocircumflex' => '00d4',
  434.     'Otilde' => '00d5',
  435.     'Odiaeresis' => '00d6',
  436.     'multiply' => '00d7',
  437.     'Ooblique' => '00d8',
  438.     'Oslash' => '00d8',
  439.     'Ugrave' => '00d9',
  440.     'Uacute' => '00da',
  441.     'Ucircumflex' => '00db',
  442.     'Udiaeresis' => '00dc',
  443.     'Yacute' => '00dd',
  444.     'THORN' => '00de',
  445.     'Thorn' => '00de',
  446.     'ssharp' => '00df',
  447.     'agrave' => '00e0',
  448.     'aacute' => '00e1',
  449.     'acircumflex' => '00e2',
  450.     'atilde' => '00e3',
  451.     'adiaeresis' => '00e4',
  452.     'aring' => '00e5',
  453.     'ae' => '00e6',
  454.     'ccedilla' => '00e7',
  455.     'egrave' => '00e8',
  456.     'eacute' => '00e9',
  457.     'ecircumflex' => '00ea',
  458.     'ediaeresis' => '00eb',
  459.     'igrave' => '00ec',
  460.     'iacute' => '00ed',
  461.     'icircumflex' => '00ee',
  462.     'idiaeresis' => '00ef',
  463.     'eth' => '00f0',
  464.     'ntilde' => '00f1',
  465.     'ograve' => '00f2',
  466.     'oacute' => '00f3',
  467.     'ocircumflex' => '00f4',
  468.     'otilde' => '00f5',
  469.     'odiaeresis' => '00f6',
  470.     'division' => '00f7',
  471.     'oslash' => '00f8',
  472.     'ooblique' => '00f8',
  473.     'ugrave' => '00f9',
  474.     'uacute' => '00fa',
  475.     'ucircumflex' => '00fb',
  476.     'udiaeresis' => '00fc',
  477.     'yacute' => '00fd',
  478.     'thorn' => '00fe',
  479.     'ydiaeresis' => '00ff',
  480.     'Amacron' => '0100',
  481.     'amacron' => '0101',
  482.     'Abreve' => '0102',
  483.     'abreve' => '0103',
  484.     'Aogonek' => '0104',
  485.     'aogonek' => '0105',
  486.     'Cacute' => '0106',
  487.     'cacute' => '0107',
  488.     'Ccircumflex' => '0108',
  489.     'ccircumflex' => '0109',
  490.     'Cabovedot' => '010a',
  491.     'cabovedot' => '010b',
  492.     'Ccaron' => '010c',
  493.     'ccaron' => '010d',
  494.     'Dcaron' => '010e',
  495.     'dcaron' => '010f',
  496.     'Dstroke' => '0110',
  497.     'dstroke' => '0111',
  498.     'Emacron' => '0112',
  499.     'emacron' => '0113',
  500.     'Eabovedot' => '0116',
  501.     'eabovedot' => '0117',
  502.     'Eogonek' => '0118',
  503.     'eogonek' => '0119',
  504.     'Ecaron' => '011a',
  505.     'ecaron' => '011b',
  506.     'Gcircumflex' => '011c',
  507.     'gcircumflex' => '011d',
  508.     'Gbreve' => '011e',
  509.     'gbreve' => '011f',
  510.     'Gabovedot' => '0120',
  511.     'gabovedot' => '0121',
  512.     'Gcedilla' => '0122',
  513.     'gcedilla' => '0123',
  514.     'Hcircumflex' => '0124',
  515.     'hcircumflex' => '0125',
  516.     'Hstroke' => '0126',
  517.     'hstroke' => '0127',
  518.     'Itilde' => '0128',
  519.     'itilde' => '0129',
  520.     'Imacron' => '012a',
  521.     'imacron' => '012b',
  522.     'Ibreve' => '012c',
  523.     'ibreve' => '012d',
  524.     'Iogonek' => '012e',
  525.     'iogonek' => '012f',
  526.     'Iabovedot' => '0130',
  527.     'idotless' => '0131',
  528.     'Jcircumflex' => '0134',
  529.     'jcircumflex' => '0135',
  530.     'Kcedilla' => '0136',
  531.     'kcedilla' => '0137',
  532.     'kra' => '0138',
  533.     'Lacute' => '0139',
  534.     'lacute' => '013a',
  535.     'Lcedilla' => '013b',
  536.     'lcedilla' => '013c',
  537.     'Lcaron' => '013d',
  538.     'lcaron' => '013e',
  539.     'Lstroke' => '0141',
  540.     'lstroke' => '0142',
  541.     'Nacute' => '0143',
  542.     'nacute' => '0144',
  543.     'Ncedilla' => '0145',
  544.     'ncedilla' => '0146',
  545.     'Ncaron' => '0147',
  546.     'ncaron' => '0148',
  547.     'ENG' => '014a',
  548.     'eng' => '014b',
  549.     'Omacron' => '014c',
  550.     'omacron' => '014d',
  551.     'Odoubleacute' => '0150',
  552.     'odoubleacute' => '0151',
  553.     'OE' => '0152',
  554.     'oe' => '0153',
  555.     'Racute' => '0154',
  556.     'racute' => '0155',
  557.     'Rcedilla' => '0156',
  558.     'rcedilla' => '0157',
  559.     'Rcaron' => '0158',
  560.     'rcaron' => '0159',
  561.     'Sacute' => '015a',
  562.     'sacute' => '015b',
  563.     'Scircumflex' => '015c',
  564.     'scircumflex' => '015d',
  565.     'Scedilla' => '015e',
  566.     'scedilla' => '015f',
  567.     'Scaron' => '0160',
  568.     'scaron' => '0161',
  569.     'Tcedilla' => '0162',
  570.     'tcedilla' => '0163',
  571.     'Tcaron' => '0164',
  572.     'tcaron' => '0165',
  573.     'Tslash' => '0166',
  574.     'tslash' => '0167',
  575.     'Utilde' => '0168',
  576.     'utilde' => '0169',
  577.     'Umacron' => '016a',
  578.     'umacron' => '016b',
  579.     'Ubreve' => '016c',
  580.     'ubreve' => '016d',
  581.     'Uring' => '016e',
  582.     'uring' => '016f',
  583.     'Udoubleacute' => '0170',
  584.     'udoubleacute' => '0171',
  585.     'Uogonek' => '0172',
  586.     'uogonek' => '0173',
  587.     'Wcircumflex' => '0174',
  588.     'wcircumflex' => '0175',
  589.     'Ycircumflex' => '0176',
  590.     'ycircumflex' => '0177',
  591.     'Ydiaeresis' => '0178',
  592.     'Zacute' => '0179',
  593.     'zacute' => '017a',
  594.     'Zabovedot' => '017b',
  595.     'zabovedot' => '017c',
  596.     'Zcaron' => '017d',
  597.     'zcaron' => '017e',
  598.     'SCHWA' => '018f',
  599.     'Schwa' => '018f', # Is this recognised by X ?
  600.     'function' => '0192',
  601.     'Obarred' => '019f',
  602.     'Ohorn' => '01a0', # Is this recognised by X ?
  603.     'ohorn' => '01a1', # Is this recognised by X ?
  604.     'Uhorn' => '01af',
  605.     'uhorn' => '01b0',
  606.     'Zstroke' => '01b5',
  607.     'zstroke' => '01b6',
  608.     'Ocaron' => '01d1',
  609.     'ocaron' => '01d2',
  610.     'Gcaron' => '01e6', # Is this recognised by X ?
  611.     'gcaron' => '01e7', # Is this recognised by X ?
  612.     'schwa' => '0259', # Is this recognised by X ?
  613.     'obarred' => '0275',
  614.     'caron' => '02c7',
  615.     'breve' => '02d8',
  616.     'abovedot' => '02d9',
  617.     'ogonek' => '02db',
  618.     'doubleacute' => '02dd',
  619.     'Greek_accentdieresis' => '0385',
  620.     'Greek_ALPHAaccent' => '0386',
  621.     'Greek_EPSILONaccent' => '0388',
  622.     'Greek_ETAaccent' => '0389',
  623.     'Greek_IOTAaccent' => '038a',
  624.     'Greek_OMICRONaccent' => '038c',
  625.     'Greek_UPSILONaccent' => '038e',
  626.     'Greek_OMEGAaccent' => '038f',
  627.     'Greek_iotaaccentdieresis' => '0390',
  628.     'Greek_ALPHA' => '0391',
  629.     'Greek_BETA' => '0392',
  630.     'Greek_GAMMA' => '0393',
  631.     'Greek_DELTA' => '0394',
  632.     'Greek_EPSILON' => '0395',
  633.     'Greek_ZETA' => '0396',
  634.     'Greek_ETA' => '0397',
  635.     'Greek_THETA' => '0398',
  636.     'Greek_IOTA' => '0399',
  637.     'Greek_KAPPA' => '039a',
  638.     'Greek_LAMBDA' => '039b',
  639.     'Greek_LAMDA' => '039b',   # Is this recognised by X ? (speling error)
  640.     'Greek_MU' => '039c',
  641.     'Greek_NU' => '039d',
  642.     'Greek_XI' => '039e',
  643.     'Greek_OMICRON' => '039f',
  644.     'Greek_PI' => '03a0',
  645.     'Greek_RHO' => '03a1',
  646.     'Greek_SIGMA' => '03a3',
  647.     'Greek_TAU' => '03a4',
  648.     'Greek_UPSILON' => '03a5',
  649.     'Greek_PHI' => '03a6',
  650.     'Greek_CHI' => '03a7',
  651.     'Greek_PSI' => '03a8',
  652.     'Greek_OMEGA' => '03a9',
  653.     'Greek_IOTAdiaeresis' => '03aa',
  654.     'Greek_UPSILONdieresis' => '03ab',
  655.     'Greek_alphaaccent' => '03ac',
  656.     'Greek_epsilonaccent' => '03ad',
  657.     'Greek_etaaccent' => '03ae',
  658.     'Greek_iotaaccent' => '03af',
  659.     'Greek_upsilonaccentdieresis' => '03b0',
  660.     'Greek_alpha' => '03b1',
  661.     'Greek_beta' => '03b2',
  662.     'Greek_gamma' => '03b3',
  663.     'Greek_delta' => '03b4',
  664.     'Greek_epsilon' => '03b5',
  665.     'Greek_zeta' => '03b6',
  666.     'Greek_eta' => '03b7',
  667.     'Greek_theta' => '03b8',
  668.     'Greek_iota' => '03b9',
  669.     'Greek_kappa' => '03ba',
  670.     'Greek_lambda' => '03bb',
  671.     'Greek_lamda' => '03bb', # Is this recognised by X ? (speling error)
  672.     'Greek_mu' => '03bc',
  673.     'Greek_nu' => '03bd',
  674.     'Greek_xi' => '03be',
  675.     'Greek_omicron' => '03bf',
  676.     'Greek_pi' => '03c0',
  677.     'Greek_rho' => '03c1',
  678.     'Greek_finalsmallsigma' => '03c2',
  679.     'Greek_sigma' => '03c3',
  680.     'Greek_tau' => '03c4',
  681.     'Greek_upsilon' => '03c5',
  682.     'Greek_phi' => '03c6',
  683.     'Greek_chi' => '03c7',
  684.     'Greek_psi' => '03c8',
  685.     'Greek_omega' => '03c9',
  686.     'Greek_iotadieresis' => '03ca',
  687.     'Greek_upsilondieresis' => '03cb',
  688.     'Greek_omicronaccent' => '03cc',
  689.     'Greek_upsilonaccent' => '03cd',
  690.     'Greek_omegaaccent' => '03ce',
  691.     'Cyrillic_IO' => '0401',
  692.     'Serbian_DJE' => '0402',
  693.     'Macedonia_GJE' => '0403',
  694.     'Ukrainian_IE' => '0404',
  695.     'Macedonia_DSE' => '0405',
  696.     'Ukrainian_I' => '0406',
  697.     'Ukrainian_YI' => '0407',
  698.     'Cyrillic_JE' => '0408',
  699.     'Cyrillic_LJE' => '0409',
  700.     'Cyrillic_NJE' => '040a',
  701.     'Serbian_TSHE' => '040b',
  702.     'Macedonia_KJE' => '040c',
  703.     'Byelorussian_SHORTU' => '040e',
  704.     'Cyrillic_DZHE' => '040f',
  705.     'Cyrillic_A' => '0410',
  706.     'Cyrillic_BE' => '0411',
  707.     'Cyrillic_VE' => '0412',
  708.     'Cyrillic_GHE' => '0413',
  709.     'Cyrillic_DE' => '0414',
  710.     'Cyrillic_IE' => '0415',
  711.     'Cyrillic_ZHE' => '0416',
  712.     'Cyrillic_ZE' => '0417',
  713.     'Cyrillic_I' => '0418',
  714.     'Cyrillic_SHORTI' => '0419',
  715.     'Cyrillic_KA' => '041a',
  716.     'Cyrillic_EL' => '041b',
  717.     'Cyrillic_EM' => '041c',
  718.     'Cyrillic_EN' => '041d',
  719.     'Cyrillic_O' => '041e',
  720.     'Cyrillic_PE' => '041f',
  721.     'Cyrillic_ER' => '0420',
  722.     'Cyrillic_ES' => '0421',
  723.     'Cyrillic_TE' => '0422',
  724.     'Cyrillic_U' => '0423',
  725.     'Cyrillic_EF' => '0424',
  726.     'Cyrillic_HA' => '0425',
  727.     'Cyrillic_TSE' => '0426',
  728.     'Cyrillic_CHE' => '0427',
  729.     'Cyrillic_SHA' => '0428',
  730.     'Cyrillic_SHCHA' => '0429',
  731.     'Cyrillic_HARDSIGN' => '042a',
  732.     'Cyrillic_YERU' => '042b',
  733.     'Cyrillic_SOFTSIGN' => '042c',
  734.     'Cyrillic_E' => '042d',
  735.     'Cyrillic_YU' => '042e',
  736.     'Cyrillic_YA' => '042f',
  737.     'Cyrillic_a' => '0430',
  738.     'Cyrillic_be' => '0431',
  739.     'Cyrillic_ve' => '0432',
  740.     'Cyrillic_ghe' => '0433',
  741.     'Cyrillic_de' => '0434',
  742.     'Cyrillic_ie' => '0435',
  743.     'Cyrillic_zhe' => '0436',
  744.     'Cyrillic_ze' => '0437',
  745.     'Cyrillic_i' => '0438',
  746.     'Cyrillic_shorti' => '0439',
  747.     'Cyrillic_ka' => '043a',
  748.     'Cyrillic_el' => '043b',
  749.     'Cyrillic_em' => '043c',
  750.     'Cyrillic_en' => '043d',
  751.     'Cyrillic_o' => '043e',
  752.     'Cyrillic_pe' => '043f',
  753.     'Cyrillic_er' => '0440',
  754.     'Cyrillic_es' => '0441',
  755.     'Cyrillic_te' => '0442',
  756.     'Cyrillic_u' => '0443',
  757.     'Cyrillic_ef' => '0444',
  758.     'Cyrillic_ha' => '0445',
  759.     'Cyrillic_tse' => '0446',
  760.     'Cyrillic_che' => '0447',
  761.     'Cyrillic_sha' => '0448',
  762.     'Cyrillic_shcha' => '0449',
  763.     'Cyrillic_hardsign' => '044a',
  764.     'Cyrillic_yeru' => '044b',
  765.     'Cyrillic_softsign' => '044c',
  766.     'Cyrillic_e' => '044d',
  767.     'Cyrillic_yu' => '044e',
  768.     'Cyrillic_ya' => '044f',
  769.     'Cyrillic_io' => '0451',
  770.     'Serbian_dje' => '0452',
  771.     'Macedonia_gje' => '0453',
  772.     'Ukrainian_ie' => '0454',
  773.     'Macedonia_dse' => '0455',
  774.     'Ukrainian_i' => '0456',
  775.     'Ukrainian_yi' => '0457',
  776.     'Cyrillic_je' => '0458',
  777.     'Cyrillic_lje' => '0459',
  778.     'Cyrillic_nje' => '045a',
  779.     'Serbian_tshe' => '045b',
  780.     'Macedonia_kje' => '045c',
  781.     'Byelorussian_shortu' => '045e',
  782.     'Cyrillic_dzhe' => '045f',
  783.     'Ukrainian_GHE_WITH_UPTURN' => '0490', # Is this recognised by X ?
  784.     'Ukrainian_ghe_with_upturn' => '0491', # Is this recognised by X ?
  785.     'Cyrillic_GHE_bar' => '0492', # Is this recognised by X ?
  786.     'Cyrillic_ghe_bar' => '0493', # Is this recognised by X ?
  787.     'Cyrillic_ZHE_descender' => '0496',
  788.     'Cyrillic_zhe_descender' => '0497',
  789.     'Cyrillic_KA_descender' => '049a', # Is this recognised by X ?
  790.     'Cyrillic_ka_descender' => '049b', # Is this recognised by X ?
  791.     'Cyrillic_KA_vertstroke' => '049c', # Is this recognised by X ?
  792.     'Cyrillic_ka_vertstroke' => '049d', # Is this recognised by X ?
  793.     'Cyrillic_EN_descender' => '04a2', # Is this recognised by X ?
  794.     'Cyrillic_en_descender' => '04a3', # Is this recognised by X ?
  795.     'Cyrillic_U_straight' => '04ae', # Is this recognised by X ?
  796.     'Cyrillic_u_straight' => '04af', # Is this recognised by X ?
  797.     'Cyrillic_U_straight_bar' => '04b0', # Is this recognised by X ?
  798.     'Cyrillic_u_straight_bar' => '04b1', # Is this recognised by X ?
  799.     'Cyrillic_HA_descender' => '04b2', # Is this recognised by X ?
  800.     'Cyrillic_ha_descender' => '04b3', # Is this recognised by X ?
  801.     'Cyrillic_CHE_descender' => '04b6',
  802.     'Cyrillic_che_descender' => '04b7',
  803.     'Cyrillic_CHE_vertstroke' => '04b8', # Is this recognised by X ?
  804.     'Cyrillic_che_vertstroke' => '04b9', # Is this recognised by X ?
  805.     'Cyrillic_SHHA' => '04ba', # Is this recognised by X ?
  806.     'Cyrillic_shha' => '04bb', # Is this recognised by X ?
  807.     'Cyrillic_SCHWA' => '04d8', # Is this recognised by X ?
  808.     'Cyrillic_schwa' => '04d9', # Is this recognised by X ?
  809.     'Cyrillic_I_macron' => '04e2',
  810.     'Cyrillic_i_macron' => '04e3',
  811.     'Cyrillic_O_bar' => '04e8', # Is this recognised by X ?
  812.     'Cyrillic_o_bar' => '04e9', # Is this recognised by X ?
  813.     'Cyrillic_U_macron' => '04ee',
  814.     'Cyrillic_u_macron' => '04ef',
  815.     'Armenian_AYB' => '0531',
  816.     'Armenian_BEN' => '0532',
  817.     'Armenian_GIM' => '0533',
  818.     'Armenian_DA' => '0534',
  819.     'Armenian_YECH' => '0535',
  820.     'Armenian_ZA' => '0536',
  821.     'Armenian_E' => '0537',
  822.     'Armenian_AT' => '0538',
  823.     'Armenian_TO' => '0539',
  824.     'Armenian_ZHE' => '053a',
  825.     'Armenian_INI' => '053b',
  826.     'Armenian_LYUN' => '053c',
  827.     'Armenian_KHE' => '053d',
  828.     'Armenian_TSA' => '053e',
  829.     'Armenian_KEN' => '053f',
  830.     'Armenian_HO' => '0540',
  831.     'Armenian_DZA' => '0541',
  832.     'Armenian_GHAT' => '0542',
  833.     'Armenian_TCHE' => '0543',
  834.     'Armenian_MEN' => '0544',
  835.     'Armenian_HI' => '0545',
  836.     'Armenian_NU' => '0546',
  837.     'Armenian_SHA' => '0547',
  838.     'Armenian_VO' => '0548',
  839.     'Armenian_CHA' => '0549',
  840.     'Armenian_PE' => '054a',
  841.     'Armenian_JE' => '054b',
  842.     'Armenian_RA' => '054c',
  843.     'Armenian_SE' => '054d',
  844.     'Armenian_VEV' => '054e',
  845.     'Armenian_TYUN' => '054f',
  846.     'Armenian_RE' => '0550',
  847.     'Armenian_TSO' => '0551',
  848.     'Armenian_VYUN' => '0552',
  849.     'Armenian_PYUR' => '0553',
  850.     'Armenian_KE' => '0554',
  851.     'Armenian_O' => '0555',
  852.     'Armenian_FE' => '0556',
  853.     'Armenian_apostrophe' => '055a',
  854.     'Armenian_accent' => '055b',
  855.     'Armenian_shesht' => '055b',
  856.     'Armenian_amanak' => '055c',
  857.     'Armenian_exclam' => '055c',
  858.     'Armenian_but' => '055d',
  859.     'Armenian_separation_mark' => '055d',
  860.     'Armenian_paruyk' => '055e',
  861.     'Armenian_question' => '055e',
  862.     'Armenian_ayb' => '0561',
  863.     'Armenian_ben' => '0562',
  864.     'Armenian_gim' => '0563',
  865.     'Armenian_da' => '0564',
  866.     'Armenian_yech' => '0565',
  867.     'Armenian_za' => '0566',
  868.     'Armenian_e' => '0567',
  869.     'Armenian_at' => '0568',
  870.     'Armenian_to' => '0569',
  871.     'Armenian_zhe' => '056a',
  872.     'Armenian_ini' => '056b',
  873.     'Armenian_lyun' => '056c',
  874.     'Armenian_khe' => '056d',
  875.     'Armenian_tsa' => '056e',
  876.     'Armenian_ken' => '056f',
  877.     'Armenian_ho' => '0570',
  878.     'Armenian_dza' => '0571',
  879.     'Armenian_ghat' => '0572',
  880.     'Armenian_tche' => '0573',
  881.     'Armenian_men' => '0574',
  882.     'Armenian_hi' => '0575',
  883.     'Armenian_nu' => '0576',
  884.     'Armenian_sha' => '0577',
  885.     'Armenian_vo' => '0578',
  886.     'Armenian_cha' => '0579',
  887.     'Armenian_pe' => '057a',
  888.     'Armenian_je' => '057b',
  889.     'Armenian_ra' => '057c',
  890.     'Armenian_se' => '057d',
  891.     'Armenian_vev' => '057e',
  892.     'Armenian_tyun' => '057f',
  893.     'Armenian_re' => '0580',
  894.     'Armenian_tso' => '0581',
  895.     'Armenian_vyun' => '0582',
  896.     'Armenian_pyur' => '0583',
  897.     'Armenian_ke' => '0584',
  898.     'Armenian_o' => '0585',
  899.     'Armenian_fe' => '0586',
  900.     'Armenian_ligature_ew' => '0587',
  901.     'Armenian_full_stop' => '0589',
  902.     'Armenian_verjaket' => '0589',
  903.     'Armenian_hyphen' => '058a',
  904.     'Armenian_yentamna' => '058a',
  905.     'hebrew_aleph' => '05d0',
  906.     'hebrew_bet' => '05d1',
  907.     'hebrew_gimel' => '05d2',
  908.     'hebrew_dalet' => '05d3',
  909.     'hebrew_he' => '05d4',
  910.     'hebrew_waw' => '05d5',
  911.     'hebrew_zain' => '05d6',
  912.     'hebrew_chet' => '05d7',
  913.     'hebrew_tet' => '05d8',
  914.     'hebrew_yod' => '05d9',
  915.     'hebrew_finalkaph' => '05da',
  916.     'hebrew_kaph' => '05db',
  917.     'hebrew_lamed' => '05dc',
  918.     'hebrew_finalmem' => '05dd',
  919.     'hebrew_mem' => '05de',
  920.     'hebrew_finalnun' => '05df',
  921.     'hebrew_nun' => '05e0',
  922.     'hebrew_samech' => '05e1',
  923.     'hebrew_ayin' => '05e2',
  924.     'hebrew_finalpe' => '05e3',
  925.     'hebrew_pe' => '05e4',
  926.     'hebrew_finalzade' => '05e5',
  927.     'hebrew_zade' => '05e6',
  928.     'hebrew_qoph' => '05e7',
  929.     'hebrew_resh' => '05e8',
  930.     'hebrew_shin' => '05e9',
  931.     'hebrew_taw' => '05ea',
  932.     'Arabic_comma' => '060c',
  933.     'Arabic_semicolon' => '061b',
  934.     'Arabic_question_mark' => '061f',
  935.     'Arabic_hamza' => '0621',
  936.     'Arabic_maddaonalef' => '0622',
  937.     'Arabic_hamzaonalef' => '0623',
  938.     'Arabic_hamzaonwaw' => '0624',
  939.     'Arabic_hamzaunderalef' => '0625',
  940.     'Arabic_hamzaonyeh' => '0626',
  941.     'Arabic_alef' => '0627',
  942.     'Arabic_beh' => '0628',
  943.     'Arabic_tehmarbuta' => '0629',
  944.     'Arabic_teh' => '062a',
  945.     'Arabic_theh' => '062b',
  946.     'Arabic_jeem' => '062c',
  947.     'Arabic_hah' => '062d',
  948.     'Arabic_khah' => '062e',
  949.     'Arabic_dal' => '062f',
  950.     'Arabic_thal' => '0630',
  951.     'Arabic_ra' => '0631',
  952.     'Arabic_zain' => '0632',
  953.     'Arabic_seen' => '0633',
  954.     'Arabic_sheen' => '0634',
  955.     'Arabic_sad' => '0635',
  956.     'Arabic_dad' => '0636',
  957.     'Arabic_tah' => '0637',
  958.     'Arabic_zah' => '0638',
  959.     'Arabic_ain' => '0639',
  960.     'Arabic_ghain' => '063a',
  961.     'Arabic_tatweel' => '0640',
  962.     'Arabic_feh' => '0641',
  963.     'Arabic_qaf' => '0642',
  964.     'Arabic_kaf' => '0643',
  965.     'Arabic_lam' => '0644',
  966.     'Arabic_meem' => '0645',
  967.     'Arabic_noon' => '0646',
  968.     'Arabic_ha' => '0647',
  969.     'Arabic_heh' => '0647', # Is this recognised by X ?
  970.     'Arabic_waw' => '0648',
  971.     'Arabic_alefmaksura' => '0649',
  972.     'Arabic_yeh' => '064a',
  973.     'Arabic_fathatan' => '064b',
  974.     'Arabic_dammatan' => '064c',
  975.     'Arabic_kasratan' => '064d',
  976.     'Arabic_fatha' => '064e',
  977.     'Arabic_damma' => '064f',
  978.     'Arabic_kasra' => '0650',
  979.     'Arabic_shadda' => '0651',
  980.     'Arabic_sukun' => '0652',
  981.     'Arabic_madda_above' => '0653', # Is this recognised by X ?
  982.     'Arabic_hamza_above' => '0654', # Is this recognised by X ?
  983.     'Arabic_hamza_below' => '0655', # Is this recognised by X ?
  984.     'Arabic_0' => '0660',
  985.     'Arabic_1' => '0661',
  986.     'Arabic_2' => '0662',
  987.     'Arabic_3' => '0663',
  988.     'Arabic_4' => '0664',
  989.     'Arabic_5' => '0665',
  990.     'Arabic_6' => '0666',
  991.     'Arabic_7' => '0667',
  992.     'Arabic_8' => '0668',
  993.     'Arabic_9' => '0669',
  994.     'Arabic_percent' => '066a',
  995.     'Arabic_superscript_alef' => '0670', # Is this recognised by X ?
  996.     'Arabic_tteh' => '0679',
  997.     'Arabic_peh' => '067e',
  998.     'Arabic_tcheh' => '0686',
  999.     'Arabic_ddal' => '0688',
  1000.     'Arabic_rreh' => '0691',
  1001.     'Arabic_jeh' => '0698',
  1002.     'Arabic_veh' => '06a4',
  1003.     'Arabic_keheh' => '06a9',
  1004.     'Arabic_gaf' => '06af',
  1005.     'Arabic_noon_ghunna' => '06ba',
  1006.     'Arabic_heh_doachashmee' => '06be',
  1007.     'Arabic_heh_goal' => '06c1',
  1008.     'Arabic_farsi_yeh' => '06cc',
  1009.     'Farsi_yeh' => '06cc',
  1010.     'Arabic_yeh_baree' => '06d2',
  1011.     'Arabic_fullstop' => '06d4',
  1012.     'Farsi_0' => '06f0',
  1013.     'Farsi_1' => '06f1',
  1014.     'Farsi_2' => '06f2',
  1015.     'Farsi_3' => '06f3',
  1016.     'Farsi_4' => '06f4',
  1017.     'Farsi_5' => '06f5',
  1018.     'Farsi_6' => '06f6',
  1019.     'Farsi_7' => '06f7',
  1020.     'Farsi_8' => '06f8',
  1021.     'Farsi_9' => '06f9',
  1022.     'Thai_kokai' => '0e01',
  1023.     'Thai_khokhai' => '0e02',
  1024.     'Thai_khokhuat' => '0e03',
  1025.     'Thai_khokhwai' => '0e04',
  1026.     'Thai_khokhon' => '0e05',
  1027.     'Thai_khorakhang' => '0e06',
  1028.     'Thai_ngongu' => '0e07',
  1029.     'Thai_chochan' => '0e08',
  1030.     'Thai_choching' => '0e09',
  1031.     'Thai_chochang' => '0e0a',
  1032.     'Thai_soso' => '0e0b',
  1033.     'Thai_chochoe' => '0e0c',
  1034.     'Thai_yoying' => '0e0d',
  1035.     'Thai_dochada' => '0e0e',
  1036.     'Thai_topatak' => '0e0f',
  1037.     'Thai_thothan' => '0e10',
  1038.     'Thai_thonangmontho' => '0e11',
  1039.     'Thai_thophuthao' => '0e12',
  1040.     'Thai_nonen' => '0e13',
  1041.     'Thai_dodek' => '0e14',
  1042.     'Thai_totao' => '0e15',
  1043.     'Thai_thothung' => '0e16',
  1044.     'Thai_thothahan' => '0e17',
  1045.     'Thai_thothong' => '0e18',
  1046.     'Thai_nonu' => '0e19',
  1047.     'Thai_bobaimai' => '0e1a',
  1048.     'Thai_popla' => '0e1b',
  1049.     'Thai_phophung' => '0e1c',
  1050.     'Thai_fofa' => '0e1d',
  1051.     'Thai_phophan' => '0e1e',
  1052.     'Thai_fofan' => '0e1f',
  1053.     'Thai_phosamphao' => '0e20',
  1054.     'Thai_moma' => '0e21',
  1055.     'Thai_yoyak' => '0e22',
  1056.     'Thai_rorua' => '0e23',
  1057.     'Thai_ru' => '0e24',
  1058.     'Thai_loling' => '0e25',
  1059.     'Thai_lu' => '0e26',
  1060.     'Thai_wowaen' => '0e27',
  1061.     'Thai_sosala' => '0e28',
  1062.     'Thai_sorusi' => '0e29',
  1063.     'Thai_sosua' => '0e2a',
  1064.     'Thai_hohip' => '0e2b',
  1065.     'Thai_lochula' => '0e2c',
  1066.     'Thai_oang' => '0e2d',
  1067.     'Thai_honokhuk' => '0e2e',
  1068.     'Thai_paiyannoi' => '0e2f',
  1069.     'Thai_saraa' => '0e30',
  1070.     'Thai_maihanakat' => '0e31',
  1071.     'Thai_saraaa' => '0e32',
  1072.     'Thai_saraam' => '0e33',
  1073.     'Thai_sarai' => '0e34',
  1074.     'Thai_saraii' => '0e35',
  1075.     'Thai_saraue' => '0e36',
  1076.     'Thai_sarauee' => '0e37',
  1077.     'Thai_sarau' => '0e38',
  1078.     'Thai_sarauu' => '0e39',
  1079.     'Thai_phinthu' => '0e3a',
  1080.     'Thai_baht' => '0e3f',
  1081.     'Thai_sarae' => '0e40',
  1082.     'Thai_saraae' => '0e41',
  1083.     'Thai_sarao' => '0e42',
  1084.     'Thai_saraaimaimuan' => '0e43',
  1085.     'Thai_saraaimaimalai' => '0e44',
  1086.     'Thai_lakkhangyao' => '0e45',
  1087.     'Thai_maiyamok' => '0e46',
  1088.     'Thai_maitaikhu' => '0e47',
  1089.     'Thai_maiek' => '0e48',
  1090.     'Thai_maitho' => '0e49',
  1091.     'Thai_maitri' => '0e4a',
  1092.     'Thai_maichattawa' => '0e4b',
  1093.     'Thai_thanthakhat' => '0e4c',
  1094.     'Thai_nikhahit' => '0e4d',
  1095.     'Thai_leksun' => '0e50',
  1096.     'Thai_leknung' => '0e51',
  1097.     'Thai_leksong' => '0e52',
  1098.     'Thai_leksam' => '0e53',
  1099.     'Thai_leksi' => '0e54',
  1100.     'Thai_lekha' => '0e55',
  1101.     'Thai_lekhok' => '0e56',
  1102.     'Thai_lekchet' => '0e57',
  1103.     'Thai_lekpaet' => '0e58',
  1104.     'Thai_lekkao' => '0e59',
  1105.     'Georgian_an' => '10d0',
  1106.     'Georgian_ban' => '10d1',
  1107.     'Georgian_gan' => '10d2',
  1108.     'Georgian_don' => '10d3',
  1109.     'Georgian_en' => '10d4',
  1110.     'Georgian_vin' => '10d5',
  1111.     'Georgian_zen' => '10d6',
  1112.     'Georgian_tan' => '10d7',
  1113.     'Georgian_in' => '10d8',
  1114.     'Georgian_kan' => '10d9',
  1115.     'Georgian_las' => '10da',
  1116.     'Georgian_man' => '10db',
  1117.     'Georgian_nar' => '10dc',
  1118.     'Georgian_on' => '10dd',
  1119.     'Georgian_par' => '10de',
  1120.     'Georgian_zhar' => '10df',
  1121.     'Georgian_rae' => '10e0',
  1122.     'Georgian_san' => '10e1',
  1123.     'Georgian_tar' => '10e2',
  1124.     'Georgian_un' => '10e3',
  1125.     'Georgian_phar' => '10e4',
  1126.     'Georgian_khar' => '10e5',
  1127.     'Georgian_ghan' => '10e6',
  1128.     'Georgian_qar' => '10e7',
  1129.     'Georgian_shin' => '10e8',
  1130.     'Georgian_chin' => '10e9',
  1131.     'Georgian_can' => '10ea',
  1132.     'Georgian_jil' => '10eb',
  1133.     'Georgian_cil' => '10ec',
  1134.     'Georgian_char' => '10ed',
  1135.     'Georgian_xan' => '10ee',
  1136.     'Georgian_jhan' => '10ef',
  1137.     'Georgian_hae' => '10f0',
  1138.     'Georgian_he' => '10f1',
  1139.     'Georgian_hie' => '10f2',
  1140.     'Georgian_we' => '10f3',
  1141.     'Georgian_har' => '10f4',
  1142.     'Georgian_hoe' => '10f5',
  1143.     'Georgian_fi' => '10f6',
  1144.     'Hangul_J_Kiyeog' => '11a8',
  1145.     'Hangul_J_SsangKiyeog' => '11a9',
  1146.     'Hangul_J_KiyeogSios' => '11aa',
  1147.     'Hangul_J_Nieun' => '11ab',
  1148.     'Hangul_J_NieunJieuj' => '11ac',
  1149.     'Hangul_J_NieunHieuh' => '11ad',
  1150.     'Hangul_J_Dikeud' => '11ae',
  1151.     'Hangul_J_Rieul' => '11af',
  1152.     'Hangul_J_RieulKiyeog' => '11b0',
  1153.     'Hangul_J_RieulMieum' => '11b1',
  1154.     'Hangul_J_RieulPieub' => '11b2',
  1155.     'Hangul_J_RieulSios' => '11b3',
  1156.     'Hangul_J_RieulTieut' => '11b4',
  1157.     'Hangul_J_RieulPhieuf' => '11b5',
  1158.     'Hangul_J_RieulHieuh' => '11b6',
  1159.     'Hangul_J_Mieum' => '11b7',
  1160.     'Hangul_J_Pieub' => '11b8',
  1161.     'Hangul_J_PieubSios' => '11b9',
  1162.     'Hangul_J_Sios' => '11ba',
  1163.     'Hangul_J_SsangSios' => '11bb',
  1164.     'Hangul_J_Ieung' => '11bc',
  1165.     'Hangul_J_Jieuj' => '11bd',
  1166.     'Hangul_J_Cieuc' => '11be',
  1167.     'Hangul_J_Khieuq' => '11bf',
  1168.     'Hangul_J_Tieut' => '11c0',
  1169.     'Hangul_J_Phieuf' => '11c1',
  1170.     'Hangul_J_Hieuh' => '11c2',
  1171.     'Hangul_J_PanSios' => '11eb',
  1172.     'Hangul_J_KkogjiDalrinIeung' => '11f0',
  1173.     'Hangul_J_YeorinHieuh' => '11f9',
  1174.     'Babovedot' => '1e02', # Is this recognised by X ?
  1175.     'babovedot' => '1e03', # Is this recognised by X ?
  1176.     'Dabovedot' => '1e0a', # Is this recognised by X ?
  1177.     'dabovedot' => '1e0b', # Is this recognised by X ?
  1178.     'Fabovedot' => '1e1e', # Is this recognised by X ?
  1179.     'fabovedot' => '1e1f', # Is this recognised by X ?
  1180.     'Lbelowdot' => '1e36',
  1181.     'lbelowdot' => '1e37',
  1182.     'Mabovedot' => '1e40', # Is this recognised by X ?
  1183.     'mabovedot' => '1e41', # Is this recognised by X ?
  1184.     'Pabovedot' => '1e56', # Is this recognised by X ?
  1185.     'pabovedot' => '1e57', # Is this recognised by X ?
  1186.     'Sabovedot' => '1e60', # Is this recognised by X ?
  1187.     'sabovedot' => '1e61', # Is this recognised by X ?
  1188.     'Tabovedot' => '1e6a', # Is this recognised by X ?
  1189.     'tabovedot' => '1e6b', # Is this recognised by X ?
  1190.     'Wgrave' => '1e80',
  1191.     'wgrave' => '1e81',
  1192.     'Wacute' => '1e82',
  1193.     'wacute' => '1e83',
  1194.     'Wdiaeresis' => '1e84',
  1195.     'wdiaeresis' => '1e85',
  1196.     'Xabovedot' => '1e8a',
  1197.     'xabovedot' => '1e8b',
  1198.     'Abelowdot' => '1ea0',
  1199.     'abelowdot' => '1ea1',
  1200.     'Ahook' => '1ea2',
  1201.     'ahook' => '1ea3',
  1202.     'Acircumflexacute' => '1ea4',
  1203.     'acircumflexacute' => '1ea5',
  1204.     'Acircumflexgrave' => '1ea6',
  1205.     'acircumflexgrave' => '1ea7',
  1206.     'Acircumflexhook' => '1ea8',
  1207.     'acircumflexhook' => '1ea9',
  1208.     'Acircumflextilde' => '1eaa',
  1209.     'acircumflextilde' => '1eab',
  1210.     'Acircumflexbelowdot' => '1eac',
  1211.     'acircumflexbelowdot' => '1ead',
  1212.     'Abreveacute' => '1eae',
  1213.     'abreveacute' => '1eaf',
  1214.     'Abrevegrave' => '1eb0',
  1215.     'abrevegrave' => '1eb1',
  1216.     'Abrevehook' => '1eb2',
  1217.     'abrevehook' => '1eb3',
  1218.     'Abrevetilde' => '1eb4',
  1219.     'abrevetilde' => '1eb5',
  1220.     'Abrevebelowdot' => '1eb6',
  1221.     'abrevebelowdot' => '1eb7',
  1222.     'Ebelowdot' => '1eb8',
  1223.     'ebelowdot' => '1eb9',
  1224.     'Ehook' => '1eba',
  1225.     'ehook' => '1ebb',
  1226.     'Etilde' => '1ebc',
  1227.     'etilde' => '1ebd',
  1228.     'Ecircumflexacute' => '1ebe',
  1229.     'ecircumflexacute' => '1ebf',
  1230.     'Ecircumflexgrave' => '1ec0',
  1231.     'ecircumflexgrave' => '1ec1',
  1232.     'Ecircumflexhook' => '1ec2',
  1233.     'ecircumflexhook' => '1ec3',
  1234.     'Ecircumflextilde' => '1ec4',
  1235.     'ecircumflextilde' => '1ec5',
  1236.     'Ecircumflexbelowdot' => '1ec6',
  1237.     'ecircumflexbelowdot' => '1ec7',
  1238.     'Ihook' => '1ec8',
  1239.     'ihook' => '1ec9',
  1240.     'Ibelowdot' => '1eca',
  1241.     'ibelowdot' => '1ecb',
  1242.     'Obelowdot' => '1ecc',
  1243.     'obelowdot' => '1ecd',
  1244.     'Ohook' => '1ece',
  1245.     'ohook' => '1ecf',
  1246.     'Ocircumflexacute' => '1ed0',
  1247.     'ocircumflexacute' => '1ed1',
  1248.     'Ocircumflexgrave' => '1ed2',
  1249.     'ocircumflexgrave' => '1ed3',
  1250.     'Ocircumflexhook' => '1ed4',
  1251.     'ocircumflexhook' => '1ed5',
  1252.     'Ocircumflextilde' => '1ed6',
  1253.     'ocircumflextilde' => '1ed7',
  1254.     'Ocircumflexbelowdot' => '1ed8',
  1255.     'ocircumflexbelowdot' => '1ed9',
  1256.     'Ohornacute' => '1eda',
  1257.     'ohornacute' => '1edb',
  1258.     'Ohorngrave' => '1edc',
  1259.     'ohorngrave' => '1edd',
  1260.     'Ohornhook' => '1ede',
  1261.     'ohornhook' => '1edf',
  1262.     'Ohorntilde' => '1ee0',
  1263.     'ohorntilde' => '1ee1',
  1264.     'Ohornbelowdot' => '1ee2',
  1265.     'ohornbelowdot' => '1ee3',
  1266.     'Ubelowdot' => '1ee4',
  1267.     'ubelowdot' => '1ee5',
  1268.     'Uhook' => '1ee6',
  1269.     'uhook' => '1ee7',
  1270.     'Uhornacute' => '1ee8',
  1271.     'uhornacute' => '1ee9',
  1272.     'Uhorngrave' => '1eea',
  1273.     'uhorngrave' => '1eeb',
  1274.     'Uhornhook' => '1eec',
  1275.     'uhornhook' => '1eed',
  1276.     'Uhorntilde' => '1eee',
  1277.     'uhorntilde' => '1eef',
  1278.     'Uhornbelowdot' => '1ef0',
  1279.     'uhornbelowdot' => '1ef1',
  1280.     'Ygrave' => '1ef2',
  1281.     'ygrave' => '1ef3',
  1282.     'Ybelowdot' => '1ef4',
  1283.     'ybelowdot' => '1ef5',
  1284.     'Yhook' => '1ef6',
  1285.     'yhook' => '1ef7',
  1286.     'Ytilde' => '1ef8',
  1287.     'ytilde' => '1ef9',
  1288.     'enspace' => '2002',
  1289.     'emspace' => '2003',
  1290.     'em3space' => '2004',
  1291.     'em4space' => '2005',
  1292.     'digitspace' => '2007',
  1293.     'punctspace' => '2008',
  1294.     'thinspace' => '2009',
  1295.     'hairspace' => '200a',
  1296.     'figdash' => '2012',
  1297.     'endash' => '2013',
  1298.     'emdash' => '2014',
  1299.     'Greek_horizbar' => '2015',
  1300.     'hebrew_doublelowline' => '2017',
  1301.     'leftsinglequotemark' => '2018',
  1302.     'rightsinglequotemark' => '2019',
  1303.     'singlelowquotemark' => '201a',
  1304.     'leftdoublequotemark' => '201c',
  1305.     'rightdoublequotemark' => '201d',
  1306.     'doublelowquotemark' => '201e',
  1307.     'dagger' => '2020',
  1308.     'doubledagger' => '2021',
  1309.     'enfilledcircbullet' => '2022',
  1310.     'doubbaselinedot' => '2025',
  1311.     'ellipsis' => '2026',
  1312.     'minutes' => '2032',
  1313.     'seconds' => '2033',
  1314.     'caret' => '2038',
  1315.     'guilsinglleft' => '2039',
  1316.     'guilsinglright' => '203a',
  1317.     'overline' => '203e',
  1318.     'zerosuperior' => '2070',
  1319.     'foursuperior' => '2074',
  1320.     'fivesuperior' => '2075',
  1321.     'sixsuperior' => '2076',
  1322.     'sevensuperior' => '2077',
  1323.     'eightsuperior' => '2078',
  1324.     'ninesuperior' => '2079',
  1325.     'zerosubscript' => '2080',
  1326.     'onesubscript' => '2081',
  1327.     'twosubscript' => '2082',
  1328.     'threesubscript' => '2083',
  1329.     'foursubscript' => '2084',
  1330.     'fivesubscript' => '2085',
  1331.     'sixsubscript' => '2086',
  1332.     'sevensubscript' => '2087',
  1333.     'eightsubscript' => '2088',
  1334.     'ninesubscript' => '2089',
  1335.     'EcuSign' => '20a0',
  1336.     'ColonSign' => '20a1',
  1337.     'CruzeiroSign' => '20a2',
  1338.     'FFrancSign' => '20a3',
  1339.     'LiraSign' => '20a4',
  1340.     'MillSign' => '20a5',
  1341.     'NairaSign' => '20a6',
  1342.     'PesetaSign' => '20a7',
  1343.     'RupeeSign' => '20a8',
  1344.     'WonSign' => '20a9',
  1345.     'Korean_Won' => '20a9',
  1346.     'NewSheqelSign' => '20aa',
  1347.     'DongSign' => '20ab', # Is this recognised by X ?
  1348.     'EuroSign' => '20ac',
  1349.     'Euro' => '20ac',
  1350.     'careof' => '2105',
  1351.     'numerosign' => '2116',
  1352.     'phonographcopyright' => '2117',
  1353.     'prescription' => '211e',
  1354.     'trademark' => '2122',
  1355.     'onethird' => '2153',
  1356.     'twothirds' => '2154',
  1357.     'onefifth' => '2155',
  1358.     'twofifths' => '2156',
  1359.     'threefifths' => '2157',
  1360.     'fourfifths' => '2158',
  1361.     'onesixth' => '2159',
  1362.     'fivesixths' => '215a',
  1363.     'oneeighth' => '215b',
  1364.     'threeeighths' => '215c',
  1365.     'fiveeighths' => '215d',
  1366.     'seveneighths' => '215e',
  1367.     'leftarrow' => '2190',
  1368.     'uparrow' => '2191',
  1369.     'rightarrow' => '2192',
  1370.     'downarrow' => '2193',
  1371.     'implies' => '21d2',
  1372.     'ifonlyif' => '21d4',
  1373.     'partialderivative' => '2202',
  1374.     'partdifferential' => '2202',
  1375.     'emptyset' => '2205',
  1376.     'nabla' => '2207',
  1377.     'elementof' => '2208',
  1378.     'notelementof' => '2209',
  1379.     'containsas' => '220B',
  1380.     'jot' => '2218',
  1381.     'radical' => '221a',
  1382.     'squareroot' => '221a',
  1383.     'cuberoot' => '221b',
  1384.     'fourthroot' => '221c',
  1385.     'variation' => '221d',
  1386.     'infinity' => '221e',
  1387.     'logicaland' => '2227',
  1388.     'upcaret' => '2227',
  1389.     'downcaret' => '2228',
  1390.     'logicalor' => '2228',
  1391.     'intersection' => '2229',
  1392.     'upshoe' => '2229',
  1393.     'downshoe' => '222a',
  1394.     'union' => '222a',
  1395.     'integral' => '222b',
  1396.     'dintegral' => '222c',
  1397.     'tintegral' => '222d',
  1398.     'therefore' => '2234',
  1399.     'because' => '2235',
  1400.     'approximate' => '223c',
  1401.     'similarequal' => '2243',
  1402.     'notapproxeq' => '2247',
  1403.     'approxeq' => '2248',
  1404.     'notidentical' => '2262',
  1405.     'notequal' => '2260',
  1406.     'identical' => '2261',
  1407.     'stricteq' => '2263',
  1408.     'lessthanequal' => '2264',
  1409.     'greaterthanequal' => '2265',
  1410.     'includedin' => '2282',
  1411.     'leftshoe' => '2282',
  1412.     'includes' => '2283',
  1413.     'rightshoe' => '2283',
  1414.     'lefttack' => '22a2',
  1415.     'righttack' => '22a3',
  1416.     'uptack' => '22a4',
  1417.     'downtack' => '22a5',
  1418.     'upstile' => '2308',
  1419.     'downstile' => '230a',
  1420.     'telephonerecorder' => '2315',
  1421.     'topintegral' => '2320',
  1422.     'botintegral' => '2321',
  1423.     'leftanglebracket' => '2329',
  1424.     'rightanglebracket' => '232a',
  1425.     'quad' => '2395',
  1426.     'topleftparens' => '239b',
  1427.     'botleftparens' => '239d',
  1428.     'toprightparens' => '239e',
  1429.     'botrightparens' => '23a0',
  1430.     'topleftsqbracket' => '23a1',
  1431.     'botleftsqbracket' => '23a3',
  1432.     'toprightsqbracket' => '23a4',
  1433.     'botrightsqbracket' => '23a6',
  1434.     'leftmiddlecurlybrace' => '23a8',
  1435.     'rightmiddlecurlybrace' => '23ac',
  1436.     'leftradical' => '23b7',
  1437.     'horizlinescan1' => '23ba',
  1438.     'horizlinescan3' => '23bb',
  1439.     'horizlinescan7' => '23bc',
  1440.     'horizlinescan9' => '23bd',
  1441.     'ht' => '2409',
  1442.     'lf' => '240a',
  1443.     'vt' => '240b',
  1444.     'ff' => '240c',
  1445.     'cr' => '240d',
  1446.     'nl' => '2424',
  1447.     'horizconnector' => '2500',
  1448.     'horizlinescan5' => '2500',
  1449.     'vertbar' => '2502',
  1450.     'vertconnector' => '2502',
  1451.     'topleftradical' => '250c',
  1452.     'upleftcorner' => '250c',
  1453.     'uprightcorner' => '2510',
  1454.     'lowleftcorner' => '2514',
  1455.     'lowrightcorner' => '2518',
  1456.     'leftt' => '251c',
  1457.     'rightt' => '2524',
  1458.     'topt' => '252c',
  1459.     'bott' => '2534',
  1460.     'crossinglines' => '253c',
  1461.     'checkerboard' => '2592',
  1462.     'enfilledsqbullet' => '25aa',
  1463.     'enopensquarebullet' => '25ab',
  1464.     'filledrectbullet' => '25ac',
  1465.     'openrectbullet' => '25ad',
  1466.     'emfilledrect' => '25ae',
  1467.     'emopenrectangle' => '25af',
  1468.     'filledtribulletup' => '25b2',
  1469.     'opentribulletup' => '25b3',
  1470.     'filledrighttribullet' => '25b6',
  1471.     'rightopentriangle' => '25b7',
  1472.     'filledtribulletdown' => '25bc',
  1473.     'opentribulletdown' => '25bd',
  1474.     'filledlefttribullet' => '25c0',
  1475.     'leftopentriangle' => '25c1',
  1476.     'soliddiamond' => '25c6',
  1477.     'circle' => '25cb',
  1478.     'emopencircle' => '25cb',
  1479.     'emfilledcircle' => '25cf',
  1480.     'enopencircbullet' => '25e6',
  1481.     'openstar' => '2606',
  1482.     'telephone' => '260e',
  1483.     'signaturemark' => '2613',
  1484.     'leftpointer' => '261c',
  1485.     'rightpointer' => '261e',
  1486.     'femalesymbol' => '2640',
  1487.     'malesymbol' => '2642',
  1488.     'club' => '2663',
  1489.     'heart' => '2665',
  1490.     'diamond' => '2666',
  1491.     'musicalflat' => '266d',
  1492.     'musicalsharp' => '266f',
  1493.     'checkmark' => '2713',
  1494.     'ballotcross' => '2717',
  1495.     'latincross' => '271d',
  1496.     'maltesecross' => '2720',
  1497.     'braille_blank' => '2800',
  1498.     'braille_dots_1' => '2801',
  1499.     'braille_dots_2' => '2802',
  1500.     'braille_dots_12' => '2803',
  1501.     'braille_dots_3' => '2804',
  1502.     'braille_dots_13' => '2805',
  1503.     'braille_dots_23' => '2806',
  1504.     'braille_dots_123' => '2807',
  1505.     'braille_dots_4' => '2808',
  1506.     'braille_dots_14' => '2809',
  1507.     'braille_dots_24' => '280a',
  1508.     'braille_dots_124' => '280b',
  1509.     'braille_dots_34' => '280c',
  1510.     'braille_dots_134' => '280d',
  1511.     'braille_dots_234' => '280e',
  1512.     'braille_dots_1234' => '280f',
  1513.     'braille_dots_5' => '2810',
  1514.     'braille_dots_15' => '2811',
  1515.     'braille_dots_25' => '2812',
  1516.     'braille_dots_125' => '2813',
  1517.     'braille_dots_35' => '2814',
  1518.     'braille_dots_135' => '2815',
  1519.     'braille_dots_235' => '2816',
  1520.     'braille_dots_1235' => '2817',
  1521.     'braille_dots_45' => '2818',
  1522.     'braille_dots_145' => '2819',
  1523.     'braille_dots_245' => '281a',
  1524.     'braille_dots_1245' => '281b',
  1525.     'braille_dots_345' => '281c',
  1526.     'braille_dots_1345' => '281d',
  1527.     'braille_dots_2345' => '281e',
  1528.     'braille_dots_12345' => '281f',
  1529.     'braille_dots_6' => '2820',
  1530.     'braille_dots_16' => '2821',
  1531.     'braille_dots_26' => '2822',
  1532.     'braille_dots_126' => '2823',
  1533.     'braille_dots_36' => '2824',
  1534.     'braille_dots_136' => '2825',
  1535.     'braille_dots_236' => '2826',
  1536.     'braille_dots_1236' => '2827',
  1537.     'braille_dots_46' => '2828',
  1538.     'braille_dots_146' => '2829',
  1539.     'braille_dots_246' => '282a',
  1540.     'braille_dots_1246' => '282b',
  1541.     'braille_dots_346' => '282c',
  1542.     'braille_dots_1346' => '282d',
  1543.     'braille_dots_2346' => '282e',
  1544.     'braille_dots_12346' => '282f',
  1545.     'braille_dots_56' => '2830',
  1546.     'braille_dots_156' => '2831',
  1547.     'braille_dots_256' => '2832',
  1548.     'braille_dots_1256' => '2833',
  1549.     'braille_dots_356' => '2834',
  1550.     'braille_dots_1356' => '2835',
  1551.     'braille_dots_2356' => '2836',
  1552.     'braille_dots_12356' => '2837',
  1553.     'braille_dots_456' => '2838',
  1554.     'braille_dots_1456' => '2839',
  1555.     'braille_dots_2456' => '283a',
  1556.     'braille_dots_12456' => '283b',
  1557.     'braille_dots_3456' => '283c',
  1558.     'braille_dots_13456' => '283d',
  1559.     'braille_dots_23456' => '283e',
  1560.     'braille_dots_123456' => '283f',
  1561.     'braille_dots_7' => '2840',
  1562.     'braille_dots_17' => '2841',
  1563.     'braille_dots_27' => '2842',
  1564.     'braille_dots_127' => '2843',
  1565.     'braille_dots_37' => '2844',
  1566.     'braille_dots_137' => '2845',
  1567.     'braille_dots_237' => '2846',
  1568.     'braille_dots_1237' => '2847',
  1569.     'braille_dots_47' => '2848',
  1570.     'braille_dots_147' => '2849',
  1571.     'braille_dots_247' => '284a',
  1572.     'braille_dots_1247' => '284b',
  1573.     'braille_dots_347' => '284c',
  1574.     'braille_dots_1347' => '284d',
  1575.     'braille_dots_2347' => '284e',
  1576.     'braille_dots_12347' => '284f',
  1577.     'braille_dots_57' => '2850',
  1578.     'braille_dots_157' => '2851',
  1579.     'braille_dots_257' => '2852',
  1580.     'braille_dots_1257' => '2853',
  1581.     'braille_dots_357' => '2854',
  1582.     'braille_dots_1357' => '2855',
  1583.     'braille_dots_2357' => '2856',
  1584.     'braille_dots_12357' => '2857',
  1585.     'braille_dots_457' => '2858',
  1586.     'braille_dots_1457' => '2859',
  1587.     'braille_dots_2457' => '285a',
  1588.     'braille_dots_12457' => '285b',
  1589.     'braille_dots_3457' => '285c',
  1590.     'braille_dots_13457' => '285d',
  1591.     'braille_dots_23457' => '285e',
  1592.     'braille_dots_123457' => '285f',
  1593.     'braille_dots_67' => '2860',
  1594.     'braille_dots_167' => '2861',
  1595.     'braille_dots_267' => '2862',
  1596.     'braille_dots_1267' => '2863',
  1597.     'braille_dots_367' => '2864',
  1598.     'braille_dots_1367' => '2865',
  1599.     'braille_dots_2367' => '2866',
  1600.     'braille_dots_12367' => '2867',
  1601.     'braille_dots_467' => '2868',
  1602.     'braille_dots_1467' => '2869',
  1603.     'braille_dots_2467' => '286a',
  1604.     'braille_dots_12467' => '286b',
  1605.     'braille_dots_3467' => '286c',
  1606.     'braille_dots_13467' => '286d',
  1607.     'braille_dots_23467' => '286e',
  1608.     'braille_dots_123467' => '286f',
  1609.     'braille_dots_567' => '2870',
  1610.     'braille_dots_1567' => '2871',
  1611.     'braille_dots_2567' => '2872',
  1612.     'braille_dots_12567' => '2873',
  1613.     'braille_dots_3567' => '2874',
  1614.     'braille_dots_13567' => '2875',
  1615.     'braille_dots_23567' => '2876',
  1616.     'braille_dots_123567' => '2877',
  1617.     'braille_dots_4567' => '2878',
  1618.     'braille_dots_14567' => '2879',
  1619.     'braille_dots_24567' => '287a',
  1620.     'braille_dots_124567' => '287b',
  1621.     'braille_dots_34567' => '287c',
  1622.     'braille_dots_134567' => '287d',
  1623.     'braille_dots_234567' => '287e',
  1624.     'braille_dots_1234567' => '287f',
  1625.     'braille_dots_8' => '2880',
  1626.     'braille_dots_18' => '2881',
  1627.     'braille_dots_28' => '2882',
  1628.     'braille_dots_128' => '2883',
  1629.     'braille_dots_38' => '2884',
  1630.     'braille_dots_138' => '2885',
  1631.     'braille_dots_238' => '2886',
  1632.     'braille_dots_1238' => '2887',
  1633.     'braille_dots_48' => '2888',
  1634.     'braille_dots_148' => '2889',
  1635.     'braille_dots_248' => '288a',
  1636.     'braille_dots_1248' => '288b',
  1637.     'braille_dots_348' => '288c',
  1638.     'braille_dots_1348' => '288d',
  1639.     'braille_dots_2348' => '288e',
  1640.     'braille_dots_12348' => '288f',
  1641.     'braille_dots_58' => '2890',
  1642.     'braille_dots_158' => '2891',
  1643.     'braille_dots_258' => '2892',
  1644.     'braille_dots_1258' => '2893',
  1645.     'braille_dots_358' => '2894',
  1646.     'braille_dots_1358' => '2895',
  1647.     'braille_dots_2358' => '2896',
  1648.     'braille_dots_12358' => '2897',
  1649.     'braille_dots_458' => '2898',
  1650.     'braille_dots_1458' => '2899',
  1651.     'braille_dots_2458' => '289a',
  1652.     'braille_dots_12458' => '289b',
  1653.     'braille_dots_3458' => '289c',
  1654.     'braille_dots_13458' => '289d',
  1655.     'braille_dots_23458' => '289e',
  1656.     'braille_dots_123458' => '289f',
  1657.     'braille_dots_68' => '28a0',
  1658.     'braille_dots_168' => '28a1',
  1659.     'braille_dots_268' => '28a2',
  1660.     'braille_dots_1268' => '28a3',
  1661.     'braille_dots_368' => '28a4',
  1662.     'braille_dots_1368' => '28a5',
  1663.     'braille_dots_2368' => '28a6',
  1664.     'braille_dots_12368' => '28a7',
  1665.     'braille_dots_468' => '28a8',
  1666.     'braille_dots_1468' => '28a9',
  1667.     'braille_dots_2468' => '28aa',
  1668.     'braille_dots_12468' => '28ab',
  1669.     'braille_dots_3468' => '28ac',
  1670.     'braille_dots_13468' => '28ad',
  1671.     'braille_dots_23468' => '28ae',
  1672.     'braille_dots_123468' => '28af',
  1673.     'braille_dots_568' => '28b0',
  1674.     'braille_dots_1568' => '28b1',
  1675.     'braille_dots_2568' => '28b2',
  1676.     'braille_dots_12568' => '28b3',
  1677.     'braille_dots_3568' => '28b4',
  1678.     'braille_dots_13568' => '28b5',
  1679.     'braille_dots_23568' => '28b6',
  1680.     'braille_dots_123568' => '28b7',
  1681.     'braille_dots_4568' => '28b8',
  1682.     'braille_dots_14568' => '28b9',
  1683.     'braille_dots_24568' => '28ba',
  1684.     'braille_dots_124568' => '28bb',
  1685.     'braille_dots_34568' => '28bc',
  1686.     'braille_dots_134568' => '28bd',
  1687.     'braille_dots_234568' => '28be',
  1688.     'braille_dots_1234568' => '28bf',
  1689.     'braille_dots_78' => '28c0',
  1690.     'braille_dots_178' => '28c1',
  1691.     'braille_dots_278' => '28c2',
  1692.     'braille_dots_1278' => '28c3',
  1693.     'braille_dots_378' => '28c4',
  1694.     'braille_dots_1378' => '28c5',
  1695.     'braille_dots_2378' => '28c6',
  1696.     'braille_dots_12378' => '28c7',
  1697.     'braille_dots_478' => '28c8',
  1698.     'braille_dots_1478' => '28c9',
  1699.     'braille_dots_2478' => '28ca',
  1700.     'braille_dots_12478' => '28cb',
  1701.     'braille_dots_3478' => '28cc',
  1702.     'braille_dots_13478' => '28cd',
  1703.     'braille_dots_23478' => '28ce',
  1704.     'braille_dots_123478' => '28cf',
  1705.     'braille_dots_578' => '28d0',
  1706.     'braille_dots_1578' => '28d1',
  1707.     'braille_dots_2578' => '28d2',
  1708.     'braille_dots_12578' => '28d3',
  1709.     'braille_dots_3578' => '28d4',
  1710.     'braille_dots_13578' => '28d5',
  1711.     'braille_dots_23578' => '28d6',
  1712.     'braille_dots_123578' => '28d7',
  1713.     'braille_dots_4578' => '28d8',
  1714.     'braille_dots_14578' => '28d9',
  1715.     'braille_dots_24578' => '28da',
  1716.     'braille_dots_124578' => '28db',
  1717.     'braille_dots_34578' => '28dc',
  1718.     'braille_dots_134578' => '28dd',
  1719.     'braille_dots_234578' => '28de',
  1720.     'braille_dots_1234578' => '28df',
  1721.     'braille_dots_678' => '28e0',
  1722.     'braille_dots_1678' => '28e1',
  1723.     'braille_dots_2678' => '28e2',
  1724.     'braille_dots_12678' => '28e3',
  1725.     'braille_dots_3678' => '28e4',
  1726.     'braille_dots_13678' => '28e5',
  1727.     'braille_dots_23678' => '28e6',
  1728.     'braille_dots_123678' => '28e7',
  1729.     'braille_dots_4678' => '28e8',
  1730.     'braille_dots_14678' => '28e9',
  1731.     'braille_dots_24678' => '28ea',
  1732.     'braille_dots_124678' => '28eb',
  1733.     'braille_dots_34678' => '28ec',
  1734.     'braille_dots_134678' => '28ed',
  1735.     'braille_dots_234678' => '28ee',
  1736.     'braille_dots_1234678' => '28ef',
  1737.     'braille_dots_5678' => '28f0',
  1738.     'braille_dots_15678' => '28f1',
  1739.     'braille_dots_25678' => '28f2',
  1740.     'braille_dots_125678' => '28f3',
  1741.     'braille_dots_35678' => '28f4',
  1742.     'braille_dots_135678' => '28f5',
  1743.     'braille_dots_235678' => '28f6',
  1744.     'braille_dots_1235678' => '28f7',
  1745.     'braille_dots_45678' => '28f8',
  1746.     'braille_dots_145678' => '28f9',
  1747.     'braille_dots_245678' => '28fa',
  1748.     'braille_dots_1245678' => '28fb',
  1749.     'braille_dots_345678' => '28fc',
  1750.     'braille_dots_1345678' => '28fd',
  1751.     'braille_dots_2345678' => '28fe',
  1752.     'braille_dots_12345678' => '28ff',
  1753.     'kana_comma' => '3001',
  1754.     'kana_fullstop' => '3002',
  1755.     'kana_openingbracket' => '300c',
  1756.     'kana_closingbracket' => '300d',
  1757.     'voicedsound' => '309b',
  1758.     'semivoicedsound' => '309c',
  1759.     'kana_a' => '30a1',
  1760.     'kana_A' => '30a2',
  1761.     'kana_i' => '30a3',
  1762.     'kana_I' => '30a4',
  1763.     'kana_u' => '30a5',
  1764.     'kana_U' => '30a6',
  1765.     'kana_e' => '30a7',
  1766.     'kana_E' => '30a8',
  1767.     'kana_o' => '30a9',
  1768.     'kana_O' => '30aa',
  1769.     'kana_KA' => '30ab',
  1770.     'kana_KI' => '30ad',
  1771.     'kana_KU' => '30af',
  1772.     'kana_KE' => '30b1',
  1773.     'kana_KO' => '30b3',
  1774.     'kana_SA' => '30b5',
  1775.     'kana_SHI' => '30b7',
  1776.     'kana_SU' => '30b9',
  1777.     'kana_SE' => '30bb',
  1778.     'kana_SO' => '30bd',
  1779.     'kana_TA' => '30bf',
  1780.     'kana_CHI' => '30c1',
  1781.     'kana_tsu' => '30c3',
  1782.     'kana_TSU' => '30c4',
  1783.     'kana_TE' => '30c6',
  1784.     'kana_TO' => '30c8',
  1785.     'kana_NA' => '30ca',
  1786.     'kana_NI' => '30cb',
  1787.     'kana_NU' => '30cc',
  1788.     'kana_NE' => '30cd',
  1789.     'kana_NO' => '30ce',
  1790.     'kana_HA' => '30cf',
  1791.     'kana_HI' => '30d2',
  1792.     'kana_FU' => '30d5',
  1793.     'kana_HE' => '30d8',
  1794.     'kana_HO' => '30db',
  1795.     'kana_MA' => '30de',
  1796.     'kana_MI' => '30df',
  1797.     'kana_MU' => '30e0',
  1798.     'kana_ME' => '30e1',
  1799.     'kana_MO' => '30e2',
  1800.     'kana_ya' => '30e3',
  1801.     'kana_YA' => '30e4',
  1802.     'kana_yu' => '30e5',
  1803.     'kana_YU' => '30e6',
  1804.     'kana_yo' => '30e7',
  1805.     'kana_YO' => '30e8',
  1806.     'kana_RA' => '30e9',
  1807.     'kana_RI' => '30ea',
  1808.     'kana_RU' => '30eb',
  1809.     'kana_RE' => '30ec',
  1810.     'kana_RO' => '30ed',
  1811.     'kana_WA' => '30ef',
  1812.     'kana_WO' => '30f2',
  1813.     'kana_N' => '30f3',
  1814.     'kana_conjunctive' => '30fb',
  1815.     'kana_middledot' => '30fb', # Is this recognised by X ?
  1816.     'prolongedsound' => '30fc',
  1817.     'Hangul_Kiyeog' => '3131',
  1818.     'Hangul_SsangKiyeog' => '3132',
  1819.     'Hangul_KiyeogSios' => '3133',
  1820.     'Hangul_Nieun' => '3134',
  1821.     'Hangul_NieunJieuj' => '3135',
  1822.     'Hangul_NieunHieuh' => '3136',
  1823.     'Hangul_Dikeud' => '3137',
  1824.     'Hangul_SsangDikeud' => '3138',
  1825.     'Hangul_Rieul' => '3139',
  1826.     'Hangul_RieulKiyeog' => '313a',
  1827.     'Hangul_RieulMieum' => '313b',
  1828.     'Hangul_RieulPieub' => '313c',
  1829.     'Hangul_RieulSios' => '313d',
  1830.     'Hangul_RieulTieut' => '313e',
  1831.     'Hangul_RieulPhieuf' => '313f',
  1832.     'Hangul_RieulHieuh' => '3140',
  1833.     'Hangul_Mieum' => '3141',
  1834.     'Hangul_Pieub' => '3142',
  1835.     'Hangul_SsangPieub' => '3143',
  1836.     'Hangul_PieubSios' => '3144',
  1837.     'Hangul_Sios' => '3145',
  1838.     'Hangul_SsangSios' => '3146',
  1839.     'Hangul_Ieung' => '3147',
  1840.     'Hangul_Jieuj' => '3148',
  1841.     'Hangul_SsangJieuj' => '3149',
  1842.     'Hangul_Cieuc' => '314a',
  1843.     'Hangul_Khieuq' => '314b',
  1844.     'Hangul_Tieut' => '314c',
  1845.     'Hangul_Phieuf' => '314d',
  1846.     'Hangul_Hieuh' => '314e',
  1847.     'Hangul_A' => '314f',
  1848.     'Hangul_AE' => '3150',
  1849.     'Hangul_YA' => '3151',
  1850.     'Hangul_YAE' => '3152',
  1851.     'Hangul_EO' => '3153',
  1852.     'Hangul_E' => '3154',
  1853.     'Hangul_YEO' => '3155',
  1854.     'Hangul_YE' => '3156',
  1855.     'Hangul_O' => '3157',
  1856.     'Hangul_WA' => '3158',
  1857.     'Hangul_WAE' => '3159',
  1858.     'Hangul_OE' => '315a',
  1859.     'Hangul_YO' => '315b',
  1860.     'Hangul_U' => '315c',
  1861.     'Hangul_WEO' => '315d',
  1862.     'Hangul_WE' => '315e',
  1863.     'Hangul_WI' => '315f',
  1864.     'Hangul_YU' => '3160',
  1865.     'Hangul_EU' => '3161',
  1866.     'Hangul_YI' => '3162',
  1867.     'Hangul_I' => '3163',
  1868.     'Hangul_RieulYeorinHieuh' => '316d',
  1869.     'Hangul_SunkyeongeumMieum' => '3171',
  1870.     'Hangul_SunkyeongeumPieub' => '3178',
  1871.     'Hangul_PanSios' => '317f',
  1872.     'Hangul_KkogjiDalrinIeung' => '3181',
  1873.     'Hangul_SunkyeongeumPhieuf' => '3184',
  1874.     'Hangul_YeorinHieuh' => '3186',
  1875.     'Hangul_AraeA' => '318d',
  1876.     'Hangul_AraeAE' => '318e',
  1877. # Keypad keys
  1878.     'KP_Multiply' => 'KP_Multiply',
  1879.     'KP_Add' => 'KP_Add',
  1880.     'KP_Seprator' => 'KP_Comma', # Is this recognised by X ?
  1881.     'KP_Separator' => 'KP_Comma',
  1882.     'KP_Subtract' => 'KP_Subtract',
  1883.     'KP_Decimal' => 'KP_Period',
  1884.     'KP_Divide' => 'KP_Divide',
  1885.     'KP_0' => 'KP_0',
  1886.     'KP_1' => 'KP_1',
  1887.     'KP_2' => 'KP_2',
  1888.     'KP_3' => 'KP_3',
  1889.     'KP_4' => 'KP_4',
  1890.     'KP_5' => 'KP_5',
  1891.     'KP_6' => 'KP_6',
  1892.     'KP_7' => 'KP_7',
  1893.     'KP_8' => 'KP_8',
  1894.     'KP_9' => 'KP_9',
  1895.     'KP_Enter' => 'KP_Enter',
  1896. # Keypad keys (alternate level)
  1897.     'KP_Home' => 'KP_7',
  1898.     'KP_Left' => 'KP_4',
  1899.     'KP_Up' => 'KP_8',
  1900.     'KP_Right' => 'KP_6',
  1901.     'KP_Down' => 'KP_2',
  1902.     'KP_Prior' => 'KP_9',
  1903.     'KP_Page_Up' => 'KP_9',
  1904.     'KP_Next' => 'KP_3',
  1905.     'KP_Page_Down' => 'KP_3',
  1906.     'KP_End' => 'KP_1',
  1907.     'KP_Begin' => 'VoidSymbol', # What does correspond to this?
  1908.     'KP_Insert' => 'KP_0',
  1909.     'KP_Delete' => 'VoidSymbol', # has to be 'KP_Period' or 'KP_Decimal'
  1910. # Keypad keys with missing support in the kernel
  1911.     'KP_Space' => 'space',
  1912.     'KP_Equal' => 'equal',
  1913.     'KP_Tab' => 'Tab',
  1914.     'KP_F1' => 'F1',
  1915.     'KP_F2' => 'F2',
  1916.     'KP_F3' => 'F3',
  1917.     'KP_F4' => 'F4',
  1918. # Dead symbols
  1919.     'dead_grave' => 'dead_grave',
  1920.     'SunFA_Grave' => 'dead_grave', # Is this recognised by X ?
  1921.     'dead_acute' => 'dead_acute',
  1922.     'SunFA_Acute' => 'dead_acute', # Is this recognised by X ?
  1923.     'dead_circumflex' => 'dead_circumflex',
  1924.     'SunFA_Circum' => 'dead_circumflex', # Is this recognised by X ?
  1925.     'dead_tilde' => 'dead_tilde',
  1926.     'SunFA_Tilde' => 'dead_tilde',
  1927.     'dead_breve' => 'dead_breve',
  1928.     'dead_diaeresis' => 'dead_diaeresis',
  1929.     'SunFA_Diaeresis' => 'dead_diaeresis', # Is this recognised by X ?
  1930.     'dead_doubleacute' => 'dead_doubleacute',
  1931.     'dead_caron' => 'dead_caron',
  1932.     'dead_cedilla' => 'dead_cedilla',
  1933.     'SunFA_Cedilla' => 'dead_cedilla', # Is this recognised by X ?
  1934.     'dead_ogonek' => 'dead_ogonek',
  1935. # Dead symbols with no support in the kernel
  1936.     'dead_macron' => '005f',         # underscore
  1937.     'dead_abovedot' => '002e',       # period
  1938.     'dead_abovering' => '002a',      # asterisk
  1939.     'dead_stroke' => '002d',         # hyphen
  1940.     'dead_belowdot' => '0323',       # ???? Vietnamese
  1941.     'dead_hook' => '0309',           # ???? Vietnamese
  1942.     'dead_iota' => '03b9',           # ???? Greek
  1943.     'dead_horn' => '031b',           # ???? Greek
  1944.     'dead_psili' => 'VoidSymbol',    # ???? Greek
  1945.     'dead_dasia' => 'VoidSymbol',    # ???? Greek
  1946. # Modifiers
  1947.     'Multi_key' => 'Compose',
  1948.     'Mode_switch' => 'ShiftL',
  1949.     'script_switch' => 'VoidSymbol',
  1950.     'Shift_L' => 'Shift',
  1951.     'Shift_R' => 'Shift',
  1952.     'Control_L' => 'Control',
  1953.     'Control_R' => 'Control',
  1954.     'Caps_Lock' => 'Caps_Lock',
  1955.     'Shift_Lock' => 'Shift_Lock',
  1956.     'Meta_L' => 'Alt',
  1957.     'Meta_R' => 'Alt',
  1958.     'Alt_L' => 'Alt',
  1959.     'Alt_R' => 'Alt',
  1960.     'Super_L' => 'Alt',
  1961.     'Super_R' => 'Alt',
  1962.     'Hyper_L' => 'Alt',
  1963.     'Hyper_R' => 'Alt',
  1964.     'ISO_Lock' => 'Caps_Lock',
  1965.     'ISO_Level2_Latch' => 'Shift',
  1966.     'ISO_Level3_Shift' => 'AltGr',
  1967.     'ISO_Level3_Latch' => 'AltGr',
  1968.     'ISO_Level3_Lock' => 'AltGr_Lock',
  1969.     'ISO_Group_Shift' => 'ShiftL',
  1970.     'ISO_Group_Latch' => 'ShiftL',
  1971.     'ISO_Group_Lock' => 'ShiftL_Lock',
  1972.     'ISO_Next_Group' => 'ShiftL_Lock',
  1973.     'ISO_Next_Group_Lock' => 'ShiftL_Lock',
  1974.     'ISO_Prev_Group' => 'ShiftL_Lock',
  1975.     'ISO_Prev_Group_Lock' => 'ShiftL_Lock',
  1976.     'ISO_First_Group' => 'ShiftL_Lock',
  1977.     'ISO_First_Group_Lock' => 'ShiftL_Lock',
  1978.     'ISO_Last_Group' => 'ShiftL_Lock',
  1979.     'ISO_Last_Group_Lock' => 'ShiftL_Lock',
  1980. # Other symbols
  1981.     'NoAction' => 'NoSymbol', # Is this recognised by X ?
  1982.     'nosymbol' => 'NoSymbol', # Is this recognised by X ?
  1983.     'Nosymbol' => 'NoSymbol', # Is this recognised by X ?
  1984.     'noSymbol' => 'NoSymbol', # Is this recognised by X ?
  1985.     'NoSymbol' => 'NoSymbol',
  1986.     'any' => 'NoSymbol', # Is this recognised by X ?
  1987.     'VoidSymbol' => 'VoidSymbol',
  1988.     'voidsymbol' => 'VoidSymbol', # Is this recognised by X ?
  1989.     'ISO_Left_Tab' => 'Tab',
  1990.     'Clear' => 'VoidSymbol',
  1991.     'Pause' => 'Pause',
  1992.     'Scroll_Lock' => 'Scroll_Lock',
  1993.     'Sys_Req' => 'VoidSymbol',
  1994.     'Delete' => 'Remove',
  1995.     'Codeinput' => 'VoidSymbol',
  1996.     'SingleCandidate' => 'VoidSymbol',
  1997.     'MultipleCandidate' => 'VoidSymbol',
  1998.     'PreviousCandidate' => 'VoidSymbol',
  1999.     'Home' => 'Home',
  2000.     'Left' => 'Left',
  2001.     'Up' => 'Up',
  2002.     'Right' => 'Right',
  2003.     'Down' => 'Down',
  2004.     'Prior' => 'Prior',
  2005.     'Page_Up' => 'PageUp',
  2006.     'Next' => 'Next',
  2007.     'Page_Down' => 'PageDown',
  2008.     'End' => 'End',
  2009.     'Begin' => 'VoidSymbol',
  2010.     'Select' => 'Select',
  2011.     'Print' => 'VoidSymbol',
  2012.     'Execute' => 'VoidSymbol',
  2013.     'Insert' => 'Insert',
  2014.     'Undo' => 'VoidSymbol',
  2015.     'Redo' => 'VoidSymbol',
  2016.     'Menu' => 'VoidSymbol',
  2017.     'Find' => 'Find',
  2018.     'Cancel' => 'VoidSymbol',
  2019.     'Help' => 'Help',
  2020.     'Break' => 'Pause',
  2021.     'Num_Lock' => 'Num_Lock',
  2022.     'F1' => 'F1',
  2023.     'F2' => 'F2',
  2024.     'F3' => 'F3',
  2025.     'F4' => 'F4',
  2026.     'F5' => 'F5',
  2027.     'F6' => 'F6',
  2028.     'F7' => 'F7',
  2029.     'F8' => 'F8',
  2030.     'F9' => 'F9',
  2031.     'F10' => 'F10',
  2032.     'F11' => 'F11',
  2033.     'L1' => 'F11',
  2034.     'F12' => 'F12',
  2035.     'L2' => 'F12',
  2036.     'F13' => 'F13',
  2037.     'L3' => 'F13',
  2038.     'F14' => 'F14',
  2039.     'L4' => 'F14',
  2040.     'F15' => 'F15',
  2041.     'L5' => 'F15',
  2042.     'F16' => 'F16',
  2043.     'L6' => 'F16',
  2044.     'F17' => 'F17',
  2045.     'L7' => 'F17',
  2046.     'F18' => 'F18',
  2047.     'L8' => 'F18',
  2048.     'F19' => 'F19',
  2049.     'L9' => 'F19',
  2050.     'F20' => 'F20',
  2051.     'L10' => 'F20',
  2052.     'F21' => 'F21',
  2053.     'R1' => 'F21',
  2054.     'F22' => 'F22',
  2055.     'R2' => 'F22',
  2056.     'F23' => 'F23',
  2057.     'R3' => 'F23',
  2058.     'F24' => 'F24',
  2059.     'R4' => 'F24',
  2060.     'F25' => 'F25',
  2061.     'R5' => 'F25',
  2062.     'F26' => 'F26',
  2063.     'R6' => 'F26',
  2064.     'F27' => 'F27',
  2065.     'R7' => 'F27',
  2066.     'F28' => 'F28',
  2067.     'R8' => 'F28',
  2068.     'F29' => 'F29',
  2069.     'R9' => 'F29',
  2070.     'F30' => 'F30',
  2071.     'R10' => 'F30',
  2072.     'F31' => 'F31',
  2073.     'R11' => 'F31',
  2074.     'F32' => 'F32',
  2075.     'R12' => 'F32',
  2076.     'F33' => 'F33',
  2077.     'R13' => 'F33',
  2078.     'F34' => 'F34',
  2079.     'R14' => 'F34',
  2080.     'F35' => 'F35',
  2081.     'R15' => 'F35',
  2082.     'Terminate_Server' => 'VoidSymbol',
  2083.     'Pointer_EnableKeys' => 'VoidSymbol',
  2084.     'XF86_Switch_VT_1' => 'VoidSymbol',
  2085.     'XF86_Switch_VT_2' => 'VoidSymbol',
  2086.     'XF86_Switch_VT_3' => 'VoidSymbol',
  2087.     'XF86_Switch_VT_4' => 'VoidSymbol',
  2088.     'XF86_Switch_VT_5' => 'VoidSymbol',
  2089.     'XF86_Switch_VT_6' => 'VoidSymbol',
  2090.     'XF86_Switch_VT_7' => 'VoidSymbol',
  2091.     'XF86_Switch_VT_8' => 'VoidSymbol',
  2092.     'XF86_Switch_VT_9' => 'VoidSymbol',
  2093.     'XF86_Switch_VT_10' => 'VoidSymbol',
  2094.     'XF86_Switch_VT_11' => 'VoidSymbol',
  2095.     'XF86_Switch_VT_12' => 'VoidSymbol',
  2096.     'XF86_ClearGrab' => 'VoidSymbol',
  2097.     'XF86_Ungrab' => 'VoidSymbol',
  2098.     'XF86_Next_VMode' => 'VoidSymbol',
  2099.     'XF86_Prev_VMode' => 'VoidSymbol',
  2100.     'XF86Copy' => 'VoidSymbol',
  2101.     'XF86Cut' => 'VoidSymbol',
  2102.     'XF86Paste' => 'VoidSymbol',
  2103.     'XF86AudioLowerVolume' => 'VoidSymbol',
  2104.     'XF86AudioRaiseVolume' => 'VoidSymbol',
  2105.     'XF86AudioMute' => 'VoidSymbol',
  2106.     'XF86PowerOff' => 'VoidSymbol',
  2107. # I do not know the Unicodes of these
  2108.     '0x1000' => 'VoidSymbol', # Special symbol for X or syntax error?
  2109.     '0x13a4' => 'VoidSymbol', # Special symbol for X or syntax error?
  2110.     '0xfe11' => 'VoidSymbol', # Special symbol for X or syntax error?
  2111.     'leftcaret' => 'VoidSymbol', # Is this recognised by X ?
  2112.     'guj_rra' => 'VoidSymbol', # Is this recognised by X ?
  2113.     'guj_nnna' => 'VoidSymbol', # Is this recognised by X ?
  2114.     'guj_llla' => 'VoidSymbol', # Is this recognised by X ?
  2115.     'gur_visarga' => 'VoidSymbol', # Is this recognised by X ?
  2116.     'gur_v_r' => 'VoidSymbol', # Is this recognised by X ?
  2117.     'gur_v_r_s' => 'VoidSymbol', # Is this recognised by X ?
  2118.     'Eisu_toggle' => 'VoidSymbol', # Is this recognised by X ?
  2119.     'Zenkaku_Hankaku' => 'VoidSymbol', # Is this recognised by X ?
  2120.     'Kanji' => 'VoidSymbol', # Is this recognised by X ?
  2121.     'Hangul' => 'VoidSymbol', # Is this recognised by X ?
  2122.     'Hangul_Hanja' => 'VoidSymbol', # Is this recognised by X ?
  2123.     'braille_dot_1' => 'VoidSymbol', # Is this recognised by X ?
  2124.     'braille_dot_2' => 'VoidSymbol', # Is this recognised by X ?
  2125.     'braille_dot_3' => 'VoidSymbol', # Is this recognised by X ?
  2126.     'braille_dot_4' => 'VoidSymbol', # Is this recognised by X ?
  2127.     'braille_dot_5' => 'VoidSymbol', # Is this recognised by X ?
  2128.     'braille_dot_6' => 'VoidSymbol', # Is this recognised by X ?
  2129.     'braille_dot_7' => 'VoidSymbol', # Is this recognised by X ?
  2130.     'braille_dot_8' => 'VoidSymbol', # Is this recognised by X ?
  2131.     'braille_dot_9' => 'VoidSymbol', # Is this recognised by X ?
  2132.     'braille_dot_10' => 'VoidSymbol', # Is this recognised by X ?
  2133. # XFree86 does not recognise these
  2134.     'SunAudioLowerVolume' => 'VoidSymbol',
  2135.     'SunAudioRaiseVolume' => 'VoidSymbol',
  2136.     'SunAudioMute' => 'VoidSymbol',
  2137.     'SunCopy' => 'VoidSymbol',
  2138.     'SunCut' => 'VoidSymbol',
  2139.     'SunPaste' => 'VoidSymbol',
  2140.     'SunAgain' => 'VoidSymbol',
  2141.     'SunUndo' => 'VoidSymbol',
  2142.     'SunFind' => 'VoidSymbol',
  2143.     'SunStop' => 'VoidSymbol',
  2144.     'SunF36' => 'VoidSymbol',
  2145.     'SunF37' => 'VoidSymbol',
  2146.     'SunFront' => 'VoidSymbol',
  2147.     'SunOpen' => 'VoidSymbol',
  2148.     'SunPowerSwitch' => 'VoidSymbol',
  2149.     'SunPowerSwitchShift' => 'VoidSymbol',
  2150.     'SunProps' => 'VoidSymbol',
  2151.     'SunSys_Req' => 'VoidSymbol',
  2152.     'SunVideoDegauss' => 'VoidSymbol',
  2153.     'SunVideoLowerBrightness' => 'VoidSymbol',
  2154.     'SunVideoRaiseBrightness' => 'VoidSymbol',
  2155. );
  2156.  
  2157. if ($compact) {
  2158.     $xkbsym_table{'Mode_switch'} = 'AltGr';
  2159.     $xkbsym_table{'ISO_Group_Shift'} = 'AltGr';
  2160.     $xkbsym_table{'ISO_Group_Latch'} = 'AltGr';
  2161.     $xkbsym_table{'ISO_Group_Lock'} = 'AltGr_Lock';
  2162.     $xkbsym_table{'ISO_Next_Group'} = 'AltGr_Lock';
  2163.     $xkbsym_table{'ISO_Next_Group_Lock'} = 'AltGr_Lock';
  2164.     $xkbsym_table{'ISO_Prev_Group'} = 'AltGr_Lock';
  2165.     $xkbsym_table{'ISO_Prev_Group_Lock'} = 'AltGr_Lock';
  2166.     $xkbsym_table{'ISO_First_Group'} = 'AltGr_Lock';
  2167.     $xkbsym_table{'ISO_First_Group_Lock'} = 'AltGr_Lock';
  2168.     $xkbsym_table{'ISO_Last_Group'} = 'AltGr_Lock';
  2169.     $xkbsym_table{'ISO_Last_Group_Lock'} = 'AltGr_Lock';
  2170. }
  2171.  
  2172. my @controlsyms;
  2173. my @metasyms;
  2174. my @metacontrolsyms;
  2175.  
  2176. {
  2177.     my %controlsyms_hash = (
  2178.     '@' => 'nul',
  2179.     'h' => 'BackSpace',
  2180.     'i' => 'Tab',
  2181.     'j' => 'Linefeed',
  2182.     '[' => 'Escape',
  2183.     '\\' => 'Control_backslash',
  2184.     ']' => 'Control_bracketright',
  2185.     '^' => 'Control_asciicircum',
  2186.     '_' => 'Control_underscore',
  2187.     chr(0x08) => 'BackSpace',
  2188.     chr(0x09) => 'Tab',
  2189.     chr(0x0a) => 'Linefeed',
  2190.     chr(0x0d) => 'Control_m',
  2191.     chr(0x1b) => 'Escape',
  2192.     chr(0x7f) => 'BackSpace', # instead of 'Delete'
  2193. # The following are Linux specific
  2194.     '2' => 'nul',
  2195.     '3' => 'Escape',
  2196.     '4' => 'Control_backslash',
  2197.     '5' => 'Control_bracketright',
  2198.     '6' => 'Control_asciicircum',
  2199.     '7' => 'Control_underscore',
  2200.     '8' => 'Delete',
  2201.     '\'' => 'Control_g', # apostrophe
  2202.     '`' => 'nul', # grave
  2203.     '.' => 'Compose',
  2204.     '?' => 'Delete',
  2205.     ' ' => 'nul',
  2206.     );
  2207.     for my $code (0 .. 255) {
  2208.     my $sym = chr ((0x41 <= $code && 0x5a >= $code) ? $code + 0x20 : $code);
  2209.     if (defined (my $special = $controlsyms_hash{$sym})) {
  2210.         $controlsyms[$code + 1] = $special;
  2211.     } elsif (0x40 <= $code && 0x5f >= $code      
  2212.         || 0x61 <= $code && 0x7a >= $code) {
  2213.         $controlsyms[$code + 1] = "Control_". $sym;
  2214.     } else {
  2215.         $controlsyms[$code + 1] = 'VoidSymbol';
  2216.     }
  2217.     }
  2218.     $controlsyms[0] = 'NoSymbol';
  2219.  
  2220.     my %metasyms_hash = (
  2221.     ' ' => 'space',
  2222.     '`' => 'grave',
  2223.     '^' => 'asciicircum',
  2224.     '~' => 'asciitilde',
  2225.     '<' => 'less',
  2226.     '=' => 'equal',
  2227.     '>' => 'greater',
  2228.     '|' => 'bar',
  2229.     '_' => 'underscore',
  2230.     '-' => 'minus',
  2231.     ',' => 'comma',
  2232.     ';' => 'semicolon',
  2233.     ':' => 'colon',
  2234.     '!' => 'exclam',
  2235.     '?' => 'question',
  2236.     '/' => 'slash',
  2237.     '.' => 'period',
  2238.     '\'' => 'apostrophe',
  2239.     '"' => 'quotedbl',
  2240.     '(' => 'parenleft',
  2241.     ')' => 'parenright',
  2242.     '[' => 'bracketleft',
  2243.     ']' => 'bracketright',
  2244.     '{' => 'braceleft',
  2245.     '}' => 'braceright',
  2246.     '@' => 'at',
  2247.     '$' => 'dollar',
  2248.     '*' => 'asterisk',
  2249.     '\\' => 'backslash',
  2250.     '&' => 'ampersand',
  2251.     '#' => 'numbersign',
  2252.     '%' => 'percent',
  2253.     '+' => 'plus',
  2254.     '0' => 'zero',
  2255.     '1' => 'one',
  2256.     '2' => 'two',
  2257.     '3' => 'three',
  2258.     '4' => 'four',
  2259.     '5' => 'five',
  2260.     '6' => 'six',
  2261.     '7' => 'seven',
  2262.     '8' => 'eight',
  2263.     '9' => 'nine',
  2264.     chr(0x08) => 'BackSpace',
  2265.     chr(0x09) => 'Tab',
  2266.     chr(0x0a) => 'Linefeed',
  2267.     chr(0x0d) => 'Control_m',
  2268.     chr(0x1b) => 'Escape',
  2269.     chr(0x7f) => 'Delete',
  2270.     );
  2271.     
  2272.     for my $code (0 .. 255) {
  2273.     my $sym = chr($code);
  2274.     if (defined (my $special = $metasyms_hash{$sym})) {
  2275.         $sym = $special;
  2276.     }
  2277.     $metasyms[$code + 1] = "Meta_". $sym;
  2278.     }
  2279.  
  2280.     $metasyms[0] = 'NoSymbol';
  2281.  
  2282.     for my $code (1 .. 256) {
  2283.     my $control = $controlsyms[$code];
  2284.     if ($control eq 'Compose') {
  2285.         $metacontrolsyms[$code] = 'Compose';
  2286.     } elsif ($control eq 'NoSymbol') {
  2287.         $metacontrolsyms[$code] = 'NoSymbol';
  2288.     } elsif ($control eq 'VoidSymbol') {
  2289.         $metacontrolsyms[$code] = 'VoidSymbol';
  2290.     } else {
  2291.         $metacontrolsyms[$code] = 'Meta_'. $control;
  2292.     }
  2293.     }
  2294.  
  2295.     $metacontrolsyms[0] = 'NoSymbol';
  2296.  
  2297. }
  2298.  
  2299. ############ GLOBAL FUNCTIONS #########################################
  2300.  
  2301. # Looks for $_[0] in the known directories and returns ready to use
  2302. # file name
  2303. sub xfilename {
  2304.     my $file = $_[0];
  2305.     (my $base = $file) =~ s/.*\/(.+)/$1/;
  2306.     for my $dir (@xdirs) {
  2307.     if (-f "$dir/$file") {
  2308.         return "$dir/$file";
  2309.     }
  2310.     if (-f "$dir/$base") {
  2311.         return "$dir/$base";
  2312.     }
  2313.     }
  2314.     die "$0: Can not find file \"$file\" in any known directory\n";
  2315. }
  2316.  
  2317. ########### READ THE RULES FILE #######################################
  2318.  
  2319. # The string $_[0] matches the pattern $_[1]. 
  2320. # The pattern may be "*", a variable name, or a plain string.
  2321. # If the string is 'OPTIONS' then match the pattern against any of the
  2322. # options from @options.
  2323. sub matches_pattern {
  2324.     my ($string, $pattern) = @_;
  2325.     if ($string eq 'OPTIONS') {
  2326.     for my $option (@options) {
  2327.         next if ($option eq '');
  2328.         if ($pattern eq $option) {
  2329.         return 1;
  2330.         }
  2331.     }
  2332.     } else {
  2333.     if ($pattern eq '*') {
  2334.         return $string ne '';
  2335.     }
  2336.     if ($pattern =~ /^\$([a-zA-Z0-9]+)$/) {
  2337.         for my $member (@{$rules_variables{$1}}) {
  2338.         if ($string eq $member) {
  2339.             return 1;
  2340.         }
  2341.         }
  2342.         return 0;
  2343.     }
  2344.     if ($string eq $pattern) {
  2345.         return 1;
  2346.     }
  2347.     }
  2348.     return 0;
  2349. }
  2350.  
  2351. if (@layouts) {
  2352.     for my $i (0 .. $#layouts) {
  2353.     if (! defined $variants[$i]) {
  2354.         $variants[$i] = '';
  2355.     }
  2356.     }
  2357.     my $rules_keycodes;
  2358.     my $rules_symbols;
  2359.     open (RULES, xfilename ("rules/$rules"))
  2360.     or die "$0: ". xfilename ("rules/$rules") .": $!\n";
  2361.     my $oldline = '';
  2362.     my @antecedents;
  2363.     my @consequents;
  2364.     my $match_found = 0;
  2365.     while (<RULES>) {
  2366.     next if (/^\s*\/\//);
  2367.     next if (/^\s*$/);
  2368.     chomp;
  2369.     s/^\s*//;
  2370.     s/\s+/ /g;
  2371.     if ($oldline) {
  2372.         $_ = $oldline . $_;
  2373.         $oldline = '';
  2374.     }
  2375.     if (s/\\$/ /) {
  2376.         $oldline = $_;
  2377.         next;
  2378.     }
  2379.     if (/^! ?\$([a-zA-Z0-9]+) ?= ?(.+)$/) {
  2380.         $rules_variables{$1} = [ split ' ', $2 ];
  2381.         next;
  2382.     }
  2383.     if (/^! ?(.+)= ?(.+)$/) {
  2384.         @antecedents = split ' ', $1;
  2385.         @consequents = split ' ', $2;
  2386.         foreach my $i (0 .. $#antecedents) {
  2387.         if ($antecedents[$i] eq 'model') {
  2388.             $antecedents[$i] = $model;
  2389.         } elsif ($antecedents[$i] eq 'layout' && @layouts == 1) {
  2390.             $antecedents[$i] = $layouts[0];
  2391.         } elsif ($antecedents[$i] =~ /layout\[([1-4])\]/) {
  2392.             if (@layouts > 1) {
  2393.             $antecedents[$i] = $layouts[$1 - 1];
  2394.             } else {
  2395.             $antecedents[$i] = '';
  2396.             }
  2397.         } elsif ($antecedents[$i] eq 'variant' && @variants == 1) {
  2398.             $antecedents[$i] = $variants[0];
  2399.         } elsif ($antecedents[$i] =~ /variant\[([1-4])\]/) {
  2400.             if (@variants > 1) {
  2401.             $antecedents[$i] = $variants[$1 - 1];
  2402.             } else {
  2403.             $antecedents[$i] = '';
  2404.             }
  2405.         } elsif ($antecedents[$i] eq 'option') {
  2406.             $antecedents[$i] = 'OPTIONS';
  2407.         } elsif ($antecedents[$i] eq 'layout'
  2408.              || $antecedents[$i] eq 'variant') {
  2409.             $antecedents[$i] = '';
  2410.         } else {
  2411.             die "Unknown name $antecedents[$i]\n";
  2412.         }
  2413.         if (! defined $antecedents[$i]) {
  2414.             $antecedents[$i] = '';
  2415.         }
  2416.         }
  2417.         $match_found = 0;
  2418.         next;
  2419.     }
  2420.     if (/^(.+)= ?(.+)$/) {
  2421.         next if ($match_found);
  2422.         my @antecedent_patterns = split ' ', $1;
  2423.         my $consequent_str = $2;
  2424.         @antecedent_patterns == @antecedents 
  2425.         or die "Bad number of antecedents";
  2426.         my $matches = 1;
  2427.         for my $i (0 .. $#antecedents) {
  2428.         if (! matches_pattern ($antecedents[$i], 
  2429.                        $antecedent_patterns[$i])) {
  2430.             $matches = 0;
  2431.             last;
  2432.         }
  2433.         }
  2434.         if ($matches) {
  2435.         $match_found = $antecedents[0] ne 'OPTIONS';
  2436.         my @consequent_values = split ' ', $2;
  2437.         @consequent_values == @consequents
  2438.             or die sprintf ("Bad number of consequents: %d != %d",
  2439.                     scalar (@consequent_values),
  2440.                     scalar (@consequents));
  2441.         for my $i (0 .. $#consequents) {
  2442.             $consequent_values[$i] =~ s/%\(/\(%/g;
  2443.             $consequent_values[$i] =~ s/%_/_%/g;
  2444.             $consequent_values[$i] =~ s/%m/$model/g;
  2445.             $consequent_values[$i] =~ s/%l\[1\]/$layouts[0]/g;
  2446.             $consequent_values[$i] =~ s/%l\[2\]/$layouts[1]/g;
  2447.             $consequent_values[$i] =~ s/%l\[3\]/$layouts[2]/g;
  2448.             $consequent_values[$i] =~ s/%l\[4\]/$layouts[3]/g;
  2449.             $consequent_values[$i] =~ s/%l/$layouts[0]/g;
  2450.             $consequent_values[$i] =~ s/%v\[1\]/$variants[0]/g;
  2451.             $consequent_values[$i] =~ s/%v\[2\]/$variants[1]/g;
  2452.             $consequent_values[$i] =~ s/%v\[3\]/$variants[2]/g;
  2453.             $consequent_values[$i] =~ s/%v\[4\]/$variants[3]/g;
  2454.             $consequent_values[$i] =~ s/%v/$variants[0]/g;
  2455.             $consequent_values[$i] =~ s/\(\)//g;
  2456.             if ($consequent_values[$i] =~ /^\+/) {
  2457.             if ($consequents[$i] eq 'keycodes') {
  2458.                 $rules_keycodes = $rules_keycodes .
  2459.                 $consequent_values[$i];
  2460.             } elsif ($consequents[$i] eq 'symbols') {
  2461.                 $rules_symbols = $rules_symbols .
  2462.                 $consequent_values[$i];
  2463.             }
  2464.             } else {
  2465.             if ($consequents[$i] eq 'keycodes') {
  2466.                 if (! $rules_keycodes) {
  2467.                 $rules_keycodes = $consequent_values[$i];
  2468.                 }
  2469.             } elsif ($consequents[$i] eq 'symbols') {
  2470.                 if (! $rules_symbols) {
  2471.                 $rules_symbols = $consequent_values[$i];
  2472.                 }
  2473.             }
  2474.             }
  2475.         }
  2476.         }
  2477.         next;
  2478.     }    
  2479.     die "Syntax error in the rules file: $_\n";
  2480.     }
  2481.     close RULES;
  2482.  
  2483.     if ($verbosity >= 1) {
  2484.     print STDERR  "Acording to the rules file:\n"
  2485.         ." keycodes = $rules_keycodes\n"
  2486.         ." symbols = $rules_symbols\n";
  2487.     }
  2488.  
  2489.     if (! $keycodes) {
  2490.     $keycodes = $rules_keycodes;
  2491.     }
  2492.     if (! $symbols) {
  2493.     $symbols = $rules_symbols;
  2494.     }
  2495. }
  2496.  
  2497. if (! $keycodes) {
  2498.     die "$0: No keycodes, nor layout specified\n";
  2499. }
  2500. if (! $symbols) {
  2501.     die "$0: No symbols, nor layout specified\n";
  2502. }
  2503.  
  2504. ########### COMPUTE ARCH ###########################################
  2505.  
  2506. if ($keycodes =~ /(^|\+|\|)macintosh\(old\)($|\+|\|)/) {
  2507.     $arch = 'macintosh';
  2508. } elsif ($keycodes =~ /(^|\+|\|)ataritt(\([^\)]*\))?($|\+|\|)/) {
  2509.     $arch = 'ataritt';
  2510. } elsif ($keycodes =~ /(^|\+|\|)amiga(\([^\)]*\))?($|\+|\|)/) {
  2511.     $arch = 'amiga';
  2512. } elsif ($keycodes =~ /(^|\+|\|)sun(\(type[45][^\)]*\))?($|\+|\|)/) {
  2513.     $arch = 'sun';
  2514. }
  2515.  
  2516. ########### READ ACM ###############################################
  2517.  
  2518. if ($charmap) {
  2519.     for my $acmfile ("${charmap}", "${charmap}.gz",
  2520.              "${charmap}.acm", "${charmap}.acm.gz",
  2521.              "/usr/share/consoletrans/${charmap}",
  2522.              "/usr/share/consoletrans/${charmap}.gz",
  2523.              "/usr/share/consoletrans/${charmap}.acm",
  2524.              "/usr/share/consoletrans/${charmap}.acm.gz",
  2525.              "acm/${charmap}.acm") {
  2526.     if (-f $acmfile) {
  2527.         $acm = $acmfile;
  2528.         last;
  2529.     }
  2530.     }
  2531.     (-f $acm) or die "$0: no ACM for ${charmap} exists\n";
  2532.     if ($acm =~ /gz$/) {
  2533.     open (ACM, '-|:utf8', "zcat $acm") or die "$0: $acm: $!\n";
  2534.     } else {
  2535.     open (ACM, '<:utf8', $acm) or die "$0: $acm: $!\n";
  2536.     }
  2537.     while (<ACM>) {
  2538.     s/\#.*//;
  2539.     chomp;
  2540.     next unless (/[^\s]/);
  2541.     if (/^\s*0x([0-9a-fA-F]{1,2})\s+\'([^\']+)\'\s*$/) {
  2542.         my $uni = ord ($2);
  2543.         my $c = hex ($1);
  2544.         $acmtable{$uni} = $c;
  2545.     } else {
  2546.         die "$0: Syntax error in ACM file: $_\n";
  2547.     }
  2548.     }
  2549.     close ACM;
  2550. }
  2551.  
  2552. # A hack to work around a bug in the kernel/loadkeys
  2553. # Disabled for Ubuntu because the cure is worse than the disease:
  2554. #   https://bugs.launchpad.net/ubuntu/+source/console-setup/+bug/69725
  2555. # However, Turkish still needs this behaviour.
  2556. if (! $acm && grep { $_ eq 'tr' } @layouts) {
  2557.     $xkbsym_table{'Caps_Lock'} = 'Shift_Lock';
  2558.     $xkbsym_table{'ISO_Lock'} = 'Shift_Lock';
  2559. }
  2560.  
  2561. ########### PARSING ###############################################
  2562.  
  2563. # Report a syntax error in $filename. $_[0] should describe what was
  2564. # expected at $stream.
  2565. sub syntax_error {
  2566.     die "$0: instead of \"". (substr ($stream, 0, 50))
  2567.     ."\" in $filename expected $_[0].\n";
  2568. }
  2569.  
  2570. # Opens the text file $_[0], reads it and saves its contents in $stream
  2571. # The comments are removed, all new lines are replaced by spaces and
  2572. # all redundant spaces are removed.
  2573. sub file_to_string {
  2574.     my $file = $_[0];
  2575.     my $string = '';
  2576.     open (FILE, "$file") or die "$0: $file: $!\n";
  2577.     while (<FILE>) {
  2578.     chomp;
  2579.     s{//.*}{};
  2580.     s{\#.*}{};
  2581.     $string = $string . $_ .' ';
  2582.     }
  2583.     close FILE;
  2584.     
  2585.     my $normalized = '';
  2586.     my $final_letter = 0;
  2587.     while ($string) {
  2588.     if ($string =~ s/^\s+// && $final_letter && $string =~ /^[a-zA-Z0-9]/) {
  2589.         $normalized = $normalized .' ';
  2590.         $final_letter = 0;
  2591.     }
  2592.     if ($string =~ s/^([^\"\s]+)//) {
  2593.         $normalized = $normalized . $1;
  2594.         $final_letter = ($1 =~ /[a-zA-Z0-9]$/);
  2595.         next;
  2596.     }
  2597.     if ($string =~ s/^(\"[^\"]*(\"|$))//) {
  2598.         $normalized = $normalized . $1;
  2599.         $final_letter = 0;
  2600.         if ($2 ne '"') {
  2601.         die "$0: missing quote in ". (substr ($1, 0, 50)) ."...\n";
  2602.         }
  2603.         next;
  2604.     }
  2605.     (! $string ) or die "Internal error";
  2606.     }
  2607.     $stream = $normalized;
  2608. }
  2609.  
  2610. # removes from $stream initial sequence of xkb flags (default, partial,
  2611. # hidden, etc.) Returns true if the "default" flag was among them.
  2612. sub xkb_flags {
  2613.     my $default = 0;
  2614.     while ($stream =~ s/^(default|partial|hidden
  2615.               |alphanumeric_keys|modifier_keys
  2616.               |keypad_keys|function_keys
  2617.               |alternate_group)\s?(.*)/$2/ix) {
  2618.     $default = 1 if ($1 =~ /default/i);
  2619.     }
  2620.     return $default;
  2621. }
  2622.  
  2623. # Removes and returns identifier from $stream. 
  2624. sub xkb_identifier {
  2625.     if ($stream =~ s/^([a-zA-Z0-1_]+) ?(.*)/$2/) {
  2626.     return $1;
  2627.     } else {
  2628.     syntax_error "identifier";
  2629.     }
  2630. }
  2631.  
  2632. # Removes and returns a string from $stream.
  2633. sub xkb_string {
  2634.     if ($stream =~ /^\"([^\"]*)\"(.*)/) {
  2635.     $stream = $2;
  2636.     return $1;
  2637.     } else {
  2638.     syntax_error "string";
  2639.     }
  2640. }
  2641.  
  2642. # Removes an include method name from $stream and returns $alternate_method,
  2643. # $augment_method, $replace_method, or $override_method.  If $stream
  2644. # does not start with a method name, return the default method (i.e. $method)
  2645. sub xkb_method {
  2646.     if ($stream =~ s/^alternate ?(.*)/$1/i) {
  2647.     return $alternate_method;
  2648.     } elsif ($stream =~ s/^augment ?(.*)/$1/i) {
  2649.     return $augment_method;
  2650.     } elsif ($stream =~ s/^replace ?(.*)/$1/i) {
  2651.     return $replace_method;
  2652.     } elsif ($stream =~ s/^override ?(.*)/$1/i) {
  2653.     return $override_method;
  2654.     } else {
  2655.     return $method;
  2656.     }
  2657. }
  2658.  
  2659. # If $stream starts with an include statement - process it and return true.
  2660. # Otherwise return false. $_[0] is the file type ("symbols" or "keycodes")
  2661. sub xkb_include {
  2662.     my $file_type = $_[0];
  2663.     if ($stream =~ s/^(include|replace|augment|override)\"([^\"]*)\";?
  2664.                         (.*)/$3/ix) {
  2665.     my $method_name = $1;
  2666.     my $include_request = $2;
  2667.     if ($method != $ignore_method) {
  2668.         my $oldmethod = $method;
  2669.         if ($method_name =~ /replace/i) {
  2670.         $method = $replace_method;
  2671.         } elsif ($method_name =~ /augment/i) {
  2672.         $method = $augment_method;
  2673.         } elsif ($method_name =~ /override/i) {
  2674.         $method = $override_method;
  2675.         }
  2676.         &include_xkb_file ($file_type, $include_request);
  2677.         $method = $oldmethod;
  2678.     }
  2679.     return 1;
  2680.     } else {
  2681.     return 0;
  2682.     }
  2683. }
  2684.  
  2685. sub xkb_keycodes_definitions {
  2686.     my $oldmethod = $method;
  2687.     while ($stream) {
  2688.     $method = $oldmethod;
  2689.  
  2690.     if (xkb_include ('keycodes')) {
  2691.         next;
  2692.     }
  2693.  
  2694.     $method = xkb_method ();
  2695.     
  2696.     if ($stream =~ (s/^(minimum|maximum|indicator|virtual\sindicator)
  2697.             [^;]*;(.*)/$2/ix)) {
  2698.         next;
  2699.     }
  2700.  
  2701.     if ($stream =~ /^<([^>]*)>=/) {
  2702.         $stream =~ s/^<([^>]+)>=([0-9]*);(.*)/$3/
  2703.         or syntax_error "keycode definition";
  2704.         my $key = $1;
  2705.         my $code = $2;
  2706.         if ($method == $replace_method
  2707.         || $method == $override_method
  2708.         || ($method == $augment_method
  2709.             && ! defined $keycodes_table{$key})) {
  2710.         $keycodes_table{$key} = [ $code ];
  2711.         delete $aliases{$key};
  2712.         } elsif ($method == $alternate_method) {
  2713.         push @{$keycodes_table{$key}}, $code;
  2714.         }
  2715.         next;
  2716.     }
  2717.     if ($stream =~ /^alias/) {
  2718.         $stream =~ s/^alias<([^>]+)>=<([^>]+)>;(.*)/$3/
  2719.         or syntax_error "alias definition";
  2720.         my $alias = $1;
  2721.         my $key = $2;
  2722.         if ($method == $replace_method
  2723.         || $method == $override_method
  2724.         || ($method == $augment_method
  2725.             && ! defined $keycodes_table{$alias})) {
  2726.         $keycodes_table{$alias} = [];
  2727.         $aliases{$alias} = $key;
  2728.         }
  2729.         next;
  2730.     }
  2731.     last;
  2732.     }
  2733.     $method = $oldmethod;
  2734. }
  2735.  
  2736. # Fill @{$symbols_table{$code}[$group]} with symbols
  2737. sub symbols_for_group {
  2738.     my $code = shift;
  2739.     my $group = shift;
  2740.     if ($method == $replace_method
  2741.     || ($method == $override_method
  2742.         && (@_ || ! defined $symbols_table{$code}[$group]))
  2743.     || ($method == $augment_method &&
  2744.         ! defined $symbols_table{$code})) {
  2745.     my $level = 0;
  2746.     for my $symbol (@_) {
  2747.         if ($symbol !~ /\(/ && $symbol =~ /./
  2748.         && (! defined $xkbsym_table{$symbol}
  2749.             || $xkbsym_table{$symbol} ne 'NoSymbol'
  2750.             || ! defined $symbols_table{$code}[$group][$level])) {
  2751.         $symbols_table{$code}[$group][$level] = $symbol;
  2752.         }
  2753.         $level++;
  2754.     }
  2755.     }
  2756. }
  2757.  
  2758. # KPDL needs a special tweak for certain layouts.
  2759. sub adjust_symbols {
  2760.     my $key = shift;
  2761.     if ($key eq 'KPDL') {
  2762.     my @newsymbols;
  2763.     for my $symbol (@_) {
  2764.         if ($symbol eq 'period') {
  2765.         push @newsymbols, 'KP_Decimal';
  2766.         } elsif ($symbol eq 'comma') {
  2767.         push @newsymbols, 'KP_Separator';
  2768.         } else {
  2769.         push @newsymbols, $symbol;
  2770.         }
  2771.     }
  2772.     return @newsymbols;
  2773.     } else {
  2774.     return @_;
  2775.     }
  2776. }
  2777.  
  2778. sub xkb_key {
  2779.     my $default_key_type = $_[0];
  2780.     if ($stream =~ /^key</i) {
  2781.     $stream =~ s/^key<([^>]+)>\{([^\}]*?)\};(.*)/$3/i
  2782.         or syntax_error "key definition";
  2783.     my $key = $1;
  2784.     my $list = $2 .",";
  2785.     if ($verbosity >= 4 && ! defined $keycodes_table{$key}) {
  2786.         warning "No scan code for <$key> is defined.\n";
  2787.     }
  2788.     for my $code (@{$keycodes_table{$key}}) {
  2789.         if ($method == $replace_method) {
  2790.         $symbols_table{$code} = [];
  2791.         }
  2792.         my $group = $base_group;
  2793.         while ($list =~ /[^ ]/) {
  2794.         # [ X1, X2, ... ]
  2795.         if ($list =~ s/^\[([^\]]*?)\],(.*)/$2/) {
  2796.             (my $symbols = $1) =~ s/,/ /g;
  2797.             my @groupsymbols = split ' ', $symbols;
  2798.             @groupsymbols = adjust_symbols $key, @groupsymbols;
  2799.             symbols_for_group $code, $group, @groupsymbols;
  2800.             $group++;
  2801.             next;
  2802.         }
  2803.         # symbols[GroupN] = [ X1, X2, ... ]
  2804.         if ($list =~ (s/^symbols\[Group([1-4])\]
  2805.                   =\[([^\]]*?)\],(.*)/$3/x)) {
  2806.             my $group = $1 - 1 + $base_group;
  2807.             (my $symbols = $2) =~ s/,/ /g;
  2808.             my @groupsymbols = split ' ', $symbols;
  2809.             @groupsymbols = adjust_symbols $key, @groupsymbols;
  2810.             symbols_for_group $code, $group, @groupsymbols;
  2811.             next;
  2812.         }
  2813.         # type = "...."
  2814.         if ($list =~ (s/^type(?:\[Group1\])?
  2815.                               =\"([^\"]+)\",(.*)/$2/x)) {
  2816.             if ($method == $replace_method
  2817.             || $method == $override_method
  2818.             || ($method == $augment_method
  2819.                 && ! defined $types_table{$code})) {
  2820.             $types_table{$code} = $1;
  2821.             }
  2822.             next;
  2823.         }
  2824.         # abracadabra
  2825.         # abracadabra = abra<cad>abra
  2826.         next if ($list =~ s/^[a-zA-Z0-9_]+(=[a-zA-Z0-9_<>]+)?,
  2827.                                    (.*)/$2/x);
  2828.         # abracadabra = "...."
  2829.         next if ($list =~ s/^[a-zA-Z0-9_]+=\"[^\"]+\",(.*)/$1/);
  2830.         # type[...] = "..."
  2831.         next if ($list =~ s/^type\[[a-zA-Z0-9_]+\]=\"[^\"]+\",
  2832.                                     (.*)/$1/x);
  2833.         die "$0: garbage in a key definition: \"$list\""
  2834.             ." in $filename.\n";
  2835.         }
  2836.         if (! defined $types_table{$code}
  2837.         || $types_table{$code} eq 'DEFAULT') {
  2838.         $types_table{$code} = $default_key_type;
  2839.         }
  2840.     }
  2841.     return 1;
  2842.     } else {
  2843.     return 0;
  2844.     }
  2845. }
  2846.  
  2847. sub xkb_symbols_definitions {
  2848.     my $oldmethod = $method;
  2849.     my $default_key_type = 'DEFAULT';
  2850.     while ($stream) {
  2851.     $method = $oldmethod;
  2852.  
  2853.     if (xkb_include ('symbols')) {
  2854.         next;
  2855.     }
  2856.  
  2857.     $method = xkb_method ();
  2858.  
  2859.     if ($stream =~ /^name/i) {
  2860.         $stream =~ s/^name\[[a-zA-Z0-9]+\]=\"[^\"]*\";(.*)/$1/i
  2861.         or syntax_error "group name";
  2862.         next;
  2863.     }
  2864.  
  2865.     if ($stream =~ (s/^key\.type(?:\[Group1\])?=\"([^\"]+)\";(.*)/$2/)) {
  2866.         $default_key_type = $1;
  2867.         next;
  2868.     }
  2869.     
  2870.     if ($stream =~ s/^[a-zA-Z0-9]+\.[a-zA-Z0-9]+=.*?;(.*)/$1/i) {
  2871.         next;
  2872.     }
  2873.  
  2874.     if ($stream =~ s/^[a-zA-Z0-9]+\.[a-zA-Z0-9]+\[[a-zA-Z0-9]+\]
  2875.                        =.*?;(.*)/$1/ix) {
  2876.         next;
  2877.     }
  2878.  
  2879.     if (xkb_key $default_key_type) {
  2880.         next;
  2881.     }
  2882.  
  2883.     if ($stream =~ /^(modifier_map|modmap|mod_map)/i) {
  2884.         $stream =~ (s/^(modifier_map|modmap|mod_map)\s?[a-zA-Z0-9_]+
  2885.             \{[^\}]*\};(.*)/$2/ix)
  2886.         or syntax_error "modifier_map";
  2887.         next;
  2888.     }
  2889.  
  2890.     if ($stream =~ /^virtual_modifiers/i) {
  2891.         $stream =~ (s/^virtual_modifiers\s?[a-zA-Z0-9_,]+;(.*)/$1/ix)
  2892.         or syntax_error "virtual_modifiers";
  2893.         next;
  2894.     }
  2895.     last;
  2896.     }
  2897.     $method = $oldmethod;
  2898. }
  2899.  
  2900. sub xkb_definitions {
  2901.     my $file_type = $_[0];
  2902.     if ($file_type eq 'symbols') {
  2903.     xkb_symbols_definitions();
  2904.     } elsif ($file_type eq 'keycodes') {
  2905.     xkb_keycodes_definitions();
  2906.     } else {
  2907.     die "$0: Bad xkb file type $file_type\n";
  2908.     }
  2909. }
  2910.  
  2911. # Remove from $stream the characters up to the first unmatched "}"
  2912. sub skip_to_brace {
  2913.     while ($stream && ($stream =~ s/^[^\}\{]*\{//)) {
  2914.     &skip_to_brace;
  2915.     }
  2916.     $stream =~ s/^[^\}\{]*(\}|$)//;
  2917. }
  2918.  
  2919. sub xkb_block_list {
  2920.     my $file_type = $_[0];
  2921.     my $block = $_[1];
  2922.     my $first = 1;
  2923.     my $ok = 0;
  2924.     my $mystream = $stream;
  2925.     while ($stream) {
  2926.     my $default = xkb_flags();
  2927.     xkb_identifier() eq "xkb_". $file_type
  2928.         or syntax_error "xkb_". $file_type;
  2929.     my $name = xkb_string();
  2930.     my $structured;
  2931.     if ($stream =~ s/^\{//) {
  2932.         $structured = 1;
  2933.     } else {
  2934.         $structured = 0;
  2935.     }
  2936.     if ($name eq $block || ($first && ! $block)) {
  2937.         xkb_definitions ($file_type);
  2938.         if ($structured) {
  2939.         $stream =~ s/^\};.*// or syntax_error "};";
  2940.         } else {
  2941.         $stream = '';
  2942.         }
  2943.         $ok = 1;
  2944.     } else {
  2945.         if ($structured) {
  2946.         skip_to_brace;
  2947.         $stream =~ s/^;// or syntax_error ";";
  2948.         } else {
  2949.         last;
  2950.         }
  2951.     }
  2952.     $first = 0;
  2953.     }
  2954.     if (! $ok) {
  2955.     $stream = $mystream;
  2956.     }
  2957.     return $ok;
  2958. }
  2959.  
  2960. sub include_xkb_file {
  2961.     my $file_type = $_[0];
  2962.     my $include_list = '^'. $_[1];
  2963.  
  2964.     my $oldmethod = $method;
  2965.     my $oldbase_group = $base_group;
  2966.     while ($include_list) {
  2967.     my $file;
  2968.     my $block;
  2969.     if ($include_list =~ (s/^(\^|\+|\|)([^\(\|\+]+)\(([^\)]+)\)
  2970.                   :([1234])(.*)/$5/x)) {
  2971.         if ($1 eq '+') {
  2972.         $method = $override_method;
  2973.         } elsif ($1 eq '|') {
  2974.         $method = $augment_method;
  2975.         }
  2976.         $file = $2;
  2977.         $block = $3;
  2978.         $base_group = $4 - 1 + $base_group;
  2979.     } elsif ($include_list =~ (s/^(\^|\+|\|)([^\(\|\+]+)\(([^\)]+)\)
  2980.                    (.*)/$4/x)) {
  2981.         if ($1 eq '+') {
  2982.         $method = $override_method;
  2983.         } elsif ($1 eq '|') {
  2984.         $method = $augment_method;
  2985.         }
  2986.         $file = $2;
  2987.         $block = $3;
  2988.     } elsif ($include_list =~ s/^(\^|\+|\|)([^\(\|\+]+):([1234])(.*)/$4/) {
  2989.         if ($1 eq '+') {
  2990.         $method = $override_method;
  2991.         } elsif ($1 eq '|') {
  2992.         $method = $augment_method;
  2993.         }
  2994.         $file = $2;
  2995.         $block = '';
  2996.         $base_group = $3 - 1 + $base_group;
  2997.     } elsif ($include_list =~ s/^(\^|\+|\|)([^\(\|\+]+)(.*)/$3/) {
  2998.         if ($1 eq '+') {
  2999.         $method = $override_method;
  3000.         } elsif ($1 eq '|') {
  3001.         $method = $augment_method;
  3002.         }
  3003.         $file = $2;
  3004.         $block = '';
  3005.     } else {
  3006.         die "$0: bad include list $include_list.\n";
  3007.     }
  3008.     
  3009.     my $oldstream = $stream;
  3010.     if ($file =~ /^\.?\//) {
  3011.         $stream = file_to_string ("$file");
  3012.     } else {
  3013.         $stream = file_to_string (xfilename "$file_type/$file");
  3014.     }
  3015.     my $oldfilename = $filename;
  3016.     $filename = $file;
  3017.     if (!xkb_block_list ($file_type, $block)) {
  3018.         warning "Can not find \"$block\" in \"$file\".\n";
  3019.         xkb_block_list ($file_type, '');
  3020.     }
  3021.     $stream = $oldstream;
  3022.     $filename = $oldfilename;
  3023.     $method = $oldmethod;
  3024.     $base_group = $oldbase_group;
  3025.     }
  3026. }
  3027.  
  3028. include_xkb_file 'keycodes', $keycodes;
  3029.  
  3030. foreach my $alias (keys %aliases) {
  3031.     if (! defined $keycodes_table{$aliases{$alias}}) {
  3032.     die "$0: undefined keyname $aliases{$alias} in ".
  3033.         "an keycode alias definition in $filename.\n";
  3034.     }
  3035.     $keycodes_table{$alias} = [ @{$keycodes_table{$alias}},
  3036.                 @{$keycodes_table{$aliases{$alias}}} ];
  3037. }
  3038.  
  3039. include_xkb_file 'symbols', $symbols;
  3040.  
  3041. foreach my $key (keys %symbols_table) {
  3042.     foreach my $group (0 .. $#{$symbols_table{$key}}) {
  3043.     if (! defined $symbols_table{$key}[$group]) {
  3044.         $symbols_table{$key}[$group] = [];
  3045.     } else {
  3046.         foreach my $level (0 .. $#{$symbols_table{$key}[$group]}) {
  3047.         if (! defined $symbols_table{$key}[$group][$level]) {
  3048.             $symbols_table{$key}[$group][$level] = 'NoSymbol';
  3049.         }
  3050.         }
  3051.     }
  3052.     }
  3053.     if (! defined $types_table{$key}) {
  3054.     $types_table{$key} = 'DEFAULT';
  3055.     }
  3056. }
  3057.  
  3058. # later we use that the distance is an even number less than 1000000
  3059. sub distance {
  3060.     my $x = $_[0];
  3061.     my $y = $_[1];
  3062.     my $bottom = $x & $y;
  3063.     # If groups differ prefer the zero group
  3064.     if (($x | 0x0f) != ($y | 0x0f)) {
  3065.     $bottom = $bottom & 0x0f;
  3066.     }
  3067.     return  ((($y - $bottom) << 6) | ($x - $bottom)) << 1;
  3068. }
  3069.  
  3070. sub uni_to_legacy {
  3071.     my $uni = $_[0];
  3072.     if ($acm) {
  3073.     if ($uni <= 0x7f) {
  3074.         return sprintf "0x%02x", $uni;
  3075.     } elsif (defined $acmtable{$uni}) {
  3076.         return sprintf "0x%02x", $acmtable{$uni};
  3077.     } else {
  3078.         if ($verbosity >= 8) {
  3079.         warning sprintf ("Unicode U+%04x does not exist "
  3080.                  ."in the legacy encoding\n", $uni);
  3081.         }
  3082.         return 'VoidSymbol';
  3083.     }
  3084.     } else {
  3085.     return 'U+'. sprintf ("%04x", $uni);
  3086.     }
  3087. }
  3088.  
  3089. sub x_to_kernelsym {
  3090.     my $xkeysym = $_[0];
  3091.     my $kernelkeysym = $xkbsym_table{$xkeysym};
  3092.     if (defined $kernelkeysym) {
  3093.         if ($kernelkeysym !~ /^[0-9a-fA-F]{4}$/) {
  3094.         return $kernelkeysym;
  3095.     }
  3096.     } else {
  3097.     $kernelkeysym = ($xkeysym =~ /^0x0?100([0-9a-fA-F]{4})$/
  3098.              ? $1
  3099.              : ($xkeysym =~ /^U([0-9a-fA-F]+)$/
  3100.                 ? $1 
  3101.                 : undef));
  3102.     }
  3103.     if (defined $kernelkeysym) {
  3104.     my $uni = hex ($kernelkeysym);
  3105.     if (defined $forbidden{$uni}) {
  3106. #        warning "Forbidden Unicode \"U+$kernelkeysym\"\n";
  3107.         return 'VoidSymbol';
  3108.     } else {
  3109.         if (chr($uni) =~ /\p{IsAlpha}/) {
  3110.         my $legacy = uni_to_legacy ($uni);
  3111.         if ($legacy ne 'VoidSymbol') {
  3112.             return '+'. $legacy;
  3113.         } else {
  3114.             return $legacy;
  3115.         }
  3116.         } elsif ($uni <= 0x1f) {
  3117.         return $controlsyms[$uni + 1];
  3118.         } else {
  3119.         return uni_to_legacy ($uni);
  3120.         }
  3121.     }
  3122.     } else {
  3123.     warning "Unknown X keysym \"$xkeysym\"\n";
  3124.     return 'VoidSymbol';
  3125.     }
  3126. }
  3127.  
  3128. sub x_to_ascii {
  3129.     my $xkeysym = $_[0];
  3130.     my $kernelkeysym = $xkbsym_table{$xkeysym};
  3131.     if (defined $kernelkeysym) {
  3132.     if ($kernelkeysym eq 'Delete') {
  3133.         return 0x7f;
  3134.     } elsif ($kernelkeysym eq 'BackSpace') {
  3135.         return 0x08;
  3136.     } elsif ($kernelkeysym eq 'Tab') {
  3137.         return 0x09;
  3138.     } elsif ($kernelkeysym eq 'Linefeed') {
  3139.         return 0x0a;
  3140.     } elsif ($kernelkeysym eq 'Return') {
  3141.         return 0x0d;
  3142.     } elsif ($kernelkeysym eq 'Escape') {
  3143.         return 0x1b;
  3144.     } elsif ($kernelkeysym eq 'NoSymbol') {
  3145.         return -1;
  3146.     } elsif ($kernelkeysym !~ /^[0-9a-fA-F]{4}$/) {
  3147.         return undef;
  3148.     }
  3149.     } else {
  3150.     $kernelkeysym = ($xkeysym =~ /^0x0?100([0-9a-fA-F]{4})/
  3151.              ? $1
  3152.              : ($xkeysym =~ /^U([0-9a-fA-F]+)/
  3153.                 ? $1 
  3154.                 : undef));
  3155.     }
  3156.     if (defined $kernelkeysym) {
  3157.     my $uni = hex ($kernelkeysym);
  3158.     if (0x00 <= $uni && 0x7f >= $uni) {
  3159.         return $uni;
  3160.     }
  3161.     }
  3162.     return undef;
  3163. }
  3164.  
  3165. # A vector of symbol codes for a key
  3166. my @vector;
  3167. # A vector with same length as @vector.  Measures how well each element of
  3168. # @vector represents the xkb symbol for the particular key.  Bigger values
  3169. # mean lower quality.
  3170. my @quality;
  3171.  
  3172. sub approximate {
  3173.     my ($coord, $new_sym, $new_quality) = @_;
  3174.     # $new_sym represents the xkb symbol for position $coord in @vector
  3175.     # with quality $new_quality
  3176.     if ((! defined $quality[$coord] 
  3177.      || $quality[$coord] > $new_quality)
  3178.     && $new_sym ne 'VoidSymbol') {
  3179.     $vector[$coord] = $new_sym;
  3180.     $quality[$coord] = $new_quality;
  3181.     }
  3182. }
  3183.  
  3184. # Fill @vector with data for key number $_[0]
  3185. sub flatten {
  3186.     #    Kernel         X
  3187.     # -----------------------------------------
  3188.     # 1  Shift          level 2 (Shift)
  3189.     # 2  AltGr          levels 3 and 4 (AltGr)
  3190.     # 4  Control        Control
  3191.     # 8  Alt            Alt
  3192.     # 0                 Group1
  3193.     # 16 ShiftL         Group2
  3194.     # 32 ShiftR         Group4
  3195.     # 48 ShiftL+ShiftR  Group3
  3196.     my $key = $_[0];
  3197.     @vector = ();
  3198.     @quality = ();
  3199.     for my $group (0..3) {
  3200.     my $real_group = $group;
  3201.     if ($real_group == 3) {
  3202.         $real_group = 2;
  3203.     } elsif ($real_group == 2) {
  3204.         $real_group = 3;
  3205.     }
  3206.     while ($real_group > $#{$symbols_table{$key}}) {
  3207.         if ($real_group >= 2) {
  3208.         $real_group = $real_group - 2;
  3209.         } else {
  3210.         $real_group = $real_group - 1;
  3211.         }
  3212.     }
  3213.     next if ($real_group < 0);
  3214.     for my $level (0..3) {
  3215.         my $real_level = $level;
  3216.         while ($real_level > $#{$symbols_table{$key}[$real_group]}) {
  3217.         if ($real_level == 2) {
  3218.             $real_level = $real_level - 2;
  3219.         } else {
  3220.             $real_level = $real_level - 1;
  3221.         }
  3222.         }
  3223.         next if ($real_level < 0);
  3224.         my $coord;
  3225.         for ($types_table{$key}) {
  3226.         if (/^(DEFAULT|ONE_LEVEL|TWO_LEVEL
  3227.                       |THREE_LEVEL|ALPHABETIC
  3228.                       |EIGHT_LEVEL|EIGHT_LEVEL_ALPHABETIC
  3229.                       |FOUR_LEVEL|FOUR_LEVEL_ALPHABETIC
  3230.                       |FOUR_LEVEL_SEMIALPHABETIC
  3231.                       |SEPARATE_CAPS_AND_SHIFT_ALPHABETIC
  3232.               |KEYPAD|FOUR_LEVEL_X|FOUR_LEVEL_MIXED_KEYPAD
  3233.               |FOUR_LEVEL_KEYPAD|LOCAL_EIGHT_LEVEL
  3234.                       |FOUR_LEVEL_PLUS_LOCK
  3235.                       )$/x) {
  3236.             # Level1: plain
  3237.             # Level2: shift
  3238.             # Level3: altgr
  3239.             # Level4: shift+altgr
  3240.             $coord = ($group << 4) + $level;
  3241.         } elsif (/^(PC_BREAK|PC_CONTROL_LEVEL2
  3242.                            |PC_LCONTROL_LEVEL2|PC_RCONTROL_LEVEL2)$/x) {
  3243.             # Level1: plain
  3244.             # Level2: control
  3245.             if ($level == 0 || $level == 2) {
  3246.             $coord = ($group << 4) + $level;
  3247.             } else {
  3248.             $coord = ($group << 4) + $level + 3;
  3249.             }
  3250.         } elsif (/^(PC_SYSRQ|PC_ALT_LEVEL2
  3251.                            |PC_LALT_LEVEL2|PC_RALT_LEVEL2)$/x) {
  3252.             # Level1: plain
  3253.             # Level2: alt
  3254.             if ($level == 0 || $level == 2) {
  3255.             $coord = ($group << 4) + $level;
  3256.             } else {
  3257.             # notice that $level is 1 or 3
  3258.             $coord = ($group << 4) + $level + 7;
  3259.             }
  3260.         } elsif (/^SHIFT\+ALT$/) {
  3261.             # Level1: plain
  3262.             # Level2: shift+alt
  3263.             if ($level == 0 || $level == 2) {
  3264.             $coord = ($group << 4) + $level;
  3265.             } else {
  3266.             $coord = ($group << 4) + $level + 8;
  3267.             }
  3268.         } elsif (/^CTRL\+ALT$/) {
  3269.             # Level1: plain
  3270.             # Level2: control+alt
  3271.             if ($level == 0 || $level == 2) {
  3272.             $coord = ($group << 4) + $level;
  3273.             } else {
  3274.             $coord = ($group << 4) + $level + 11;
  3275.             }
  3276.         } else {
  3277.             warning "Unknown key type $types_table{$key}\n";
  3278.             $coord = ($group << 4) + $level;
  3279.         }
  3280.         }
  3281.         my $xkeysym = $symbols_table{$key}[$real_group][$real_level];
  3282.         my $is_special = ($xkeysym !~ /^U[0-9a-fA-F]+$/
  3283.                   && defined $xkbsym_table{$xkeysym}
  3284.                   && ($xkbsym_table{$xkeysym}
  3285.                   !~ /^[0-9a-fA-F]{4}$/));
  3286.         my $kernelkeysym = x_to_kernelsym ($xkeysym);
  3287.         my $ascii = x_to_ascii ($xkeysym);
  3288.         approximate ($coord, $kernelkeysym, 0);
  3289.         for my $approximated_group (0 .. 3) {
  3290.         for my $approximated_level (0 .. 3) {
  3291.             my $approximated_coord = ($approximated_level
  3292.                           + ($approximated_group << 4));
  3293.             my $distance = distance ($approximated_coord, $coord);
  3294.             approximate ($approximated_coord,
  3295.                  $kernelkeysym, $distance);
  3296.             if (defined $ascii) {
  3297.             approximate (($approximated_coord | 0x08), 
  3298.                      $metasyms[$ascii + 1], $distance + 1);
  3299.             approximate (($approximated_coord | 0x04), 
  3300.                      $controlsyms[$ascii + 1], $distance + 1);
  3301.             approximate (($approximated_coord | 0x0c), 
  3302.                      $metacontrolsyms[$ascii + 1], 
  3303.                      $distance + 1);
  3304.             } elsif ($is_special) {
  3305.             approximate (($approximated_coord | 0x08), 
  3306.                      $kernelkeysym, $distance + 1);
  3307.             approximate (($approximated_coord | 0x04), 
  3308.                      $kernelkeysym, $distance + 1);
  3309.             approximate (($approximated_coord | 0x0c), 
  3310.                      $kernelkeysym, $distance + 1);
  3311.             }
  3312.         }
  3313.         }
  3314.     }
  3315.     }
  3316.     for my $coord (0 .. 63) {
  3317.     if (! defined $vector[$coord]) {
  3318.         $vector[$coord] = 'VoidSymbol';
  3319.     }
  3320.     }
  3321.  
  3322.     for my $coord (0 .. 63) {
  3323.     next if ($coord & 0x0c); # If Control and/or Alt
  3324.     my $mask = $kernel_modifiers{$vector[$coord]};
  3325.     next unless (defined $mask);
  3326.     for my $mod (4, 8, 12) {
  3327.         if ($vector[$coord + $mod] eq 'VoidSymbol'
  3328.         && ($vector[($coord + $mod) ^ $mask] eq 'VoidSymbol')) {
  3329.         $vector[$coord + $mod] = $vector[$coord];
  3330.         }
  3331.     }
  3332.     }
  3333.     
  3334.     # Without this it would be possible to lock permanently
  3335.     # the modifier key such as Control or Alt
  3336.     for my $coord (0 .. 63) {
  3337.     my $mask = $kernel_modifiers{$vector[$coord]};
  3338.     if (defined $mask) {
  3339.         $vector[$coord ^ $mask] = $vector[$coord];
  3340.         if ($compact) {
  3341.         # AltGr = 0x02,  ShiftL = 0x10
  3342.         if (($mask & 0x02) && ($mask & 0x10)) {
  3343.             $vector[$coord ^ $mask ^ 0x02] = $vector[$coord];
  3344.             $vector[$coord ^ $mask ^ 0x10] = $vector[$coord];
  3345.         } elsif ($mask & 0x02) {
  3346.             $vector[$coord ^ $mask ^ 0x10] = $vector[$coord];
  3347.             $vector[$coord ^ $mask ^ 0x10 ^ 0x02] = $vector[$coord];
  3348.         } elsif ($mask & 0x10) {
  3349.             $vector[$coord ^ $mask ^ 0x02] = $vector[$coord];
  3350.             $vector[$coord ^ $mask ^ 0x02 ^ 0x10] = $vector[$coord];
  3351.         }
  3352.         }
  3353.     }
  3354.     }
  3355.     
  3356.     if (! $compact) {
  3357.     for my $coord (16 .. 63) {
  3358.         if ($vector[$coord] =~ /^(ShiftL|ShiftL_Lock)$/) {
  3359.         $vector[$coord] = 'VoidSymbol';
  3360.         }
  3361.     }
  3362.     for my $coord (0 .. 15) {
  3363.         if ($vector[$coord] eq 'ShiftL_Lock') {   #  0 => 16
  3364.         $vector[$coord + 16] = 'ShiftR_Lock'; # 16 => 48
  3365.         $vector[$coord + 32] = 'ShiftR_Lock'; # 32 => 0
  3366.         $vector[$coord + 48] = 'ShiftL_Lock'; # 48 => 32
  3367.         } elsif ($vector[$coord] eq 'ShiftL') {
  3368.         $vector[$coord + 16] = 'ShiftL';
  3369.         $vector[$coord + 32] = 'ShiftL';
  3370.         $vector[$coord + 48] = 'ShiftL';
  3371.         }
  3372.     }
  3373.     } else {
  3374.     for my $coord (16 .. 63) {
  3375.         if ($vector[$coord] =~ /^(AltGr|AltGr_Lock)$/) {
  3376.         $vector[$coord] = 'VoidSymbol';
  3377.         }
  3378.     }
  3379.     for my $coord (0 .. 15) {
  3380.         if ($vector[$coord] eq 'AltGr_Lock') {
  3381.         $vector[$coord + 16] = 'AltGr_Lock';
  3382.         $vector[$coord + 32] = 'AltGr_Lock';
  3383.         $vector[$coord + 48] = 'AltGr_Lock';
  3384.         } elsif ($vector[$coord] eq 'AltGr') {
  3385.         $vector[$coord + 16] = 'AltGr';
  3386.         $vector[$coord + 32] = 'AltGr';
  3387.         $vector[$coord + 48] = 'AltGr';
  3388.         }
  3389.     }
  3390.     }
  3391.  
  3392.     for my $group (0 .. 3) {
  3393.     my $kp = undef;
  3394.     for my $x (0 .. 15) {
  3395.         my $coord = 16 * $group + $x;
  3396.         if ($vector[$coord] =~ /^KP_/) {
  3397.         $kp = $vector[$coord];
  3398.         last;
  3399.         }
  3400.     }
  3401.     if ($types_table{$key} =~ /^(KEYPAD|FOUR_LEVEL_X
  3402.                                     |FOUR_LEVEL_MIXED_KEYPAD
  3403.                             |FOUR_LEVEL_KEYPAD)$/x
  3404.         && ! defined $kp) {
  3405.         $kp = 'VoidSymbol';
  3406.     }
  3407.     if ($kp) {
  3408.         for my $x (0 .. 15) {
  3409.         my $coord = 16 * $group + $x;
  3410.         for ($vector[$coord]) {
  3411.             if (/^VoidSymbol$/) {
  3412.             # KP_Begin and KP_Delete are mapped to VoidSymbol
  3413.             $vector[$coord] = $kp;
  3414.             } elsif (/$xkbsym_table{'plus'}/) {# not anchored match!
  3415.             $vector[$coord] = 'KP_Add';
  3416.             } elsif (/$xkbsym_table{'minus'}/) {
  3417.             $vector[$coord] = 'KP_Subtract';
  3418.             } elsif (/$xkbsym_table{'asterisk'}/) {
  3419.             $vector[$coord] = 'KP_Multiply';
  3420.             } elsif (/$xkbsym_table{'slash'}/) {
  3421.             $vector[$coord] = 'KP_Divide';
  3422.             } elsif (/$xkbsym_table{'comma'}/) {
  3423.             $vector[$coord] = 'KP_Comma';
  3424.             } elsif (/$xkbsym_table{'period'}/) {
  3425.             $vector[$coord] = 'KP_Period';
  3426.             } elsif (/$xkbsym_table{'0'}/) {
  3427.             $vector[$coord] = 'KP_0';
  3428.             } elsif (/$xkbsym_table{'1'}/) {
  3429.             $vector[$coord] = 'KP_1';
  3430.             } elsif (/$xkbsym_table{'2'}/) {
  3431.             $vector[$coord] = 'KP_2';
  3432.             } elsif (/$xkbsym_table{'3'}/) {
  3433.             $vector[$coord] = 'KP_3';
  3434.             } elsif (/$xkbsym_table{'4'}/) {
  3435.             $vector[$coord] = 'KP_4';
  3436.             } elsif (/$xkbsym_table{'5'}/) {
  3437.             $vector[$coord] = 'KP_5';
  3438.             } elsif (/$xkbsym_table{'6'}/) {
  3439.             $vector[$coord] = 'KP_6';
  3440.             } elsif (/$xkbsym_table{'7'}/) {
  3441.             $vector[$coord] = 'KP_7';
  3442.             } elsif (/$xkbsym_table{'8'}/) {
  3443.             $vector[$coord] = 'KP_8';
  3444.             } elsif (/$xkbsym_table{'9'}/) {
  3445.             $vector[$coord] = 'KP_9';
  3446.             } elsif (/^(Return|Enter)$/) {
  3447.             $vector[$coord] = 'KP_Enter';
  3448.             } elsif (/^Home$/) {
  3449.             $vector[$coord] = 'KP_7';
  3450.             } elsif (/^Left$/) {
  3451.             $vector[$coord] = 'KP_4';
  3452.             } elsif (/^Up$/) {
  3453.             $vector[$coord] = 'KP_8';
  3454.             } elsif (/^Right$/) {
  3455.             $vector[$coord] = 'KP_6';
  3456.             } elsif (/^Down$/) {
  3457.             $vector[$coord] = 'KP_2';
  3458.             } elsif (/^Prior$/) {
  3459.             $vector[$coord] = 'KP_9';
  3460.             } elsif (/^Next$/) {
  3461.             $vector[$coord] = 'KP_3';
  3462.             } elsif (/^End$/) {
  3463.             $vector[$coord] = 'KP_1';
  3464.             } elsif (/^Insert$/) {
  3465.             $vector[$coord] = 'KP_0';
  3466.             }
  3467.         }
  3468.         }
  3469.     }
  3470.     }
  3471.  
  3472.     for my $group (0 .. 3) {
  3473.     my $coord = $group << 4;
  3474.     my $mainsym = $vector[$coord];
  3475.     if ($mainsym =~ /^F([0-9]+)$/) {
  3476.         my $num = $1;
  3477.         $vector[$coord + 1] = 'F'. ($num + 10);
  3478.         $vector[$coord + 2] = 'F'. ($num + 40);
  3479.         $vector[$coord + 3] = 'F'. ($num + 50);
  3480.         $vector[$coord + 4] = 'F'. ($num + 20);
  3481.         $vector[$coord + 5] = 'F'. ($num + 30);
  3482.         $vector[$coord + 6] = 'F'. ($num + 60);
  3483.         $vector[$coord + 7] = 'F'. ($num + 70);
  3484.         $vector[$coord + 8] = 'Console_'. $num;
  3485.         $vector[$coord + 9] = 'Console_'. ($num + 10);
  3486.         $vector[$coord + 12] = 'Console_'. $num;
  3487.         $vector[$coord + 13] = 'Console_'. ($num + 10);
  3488.     } elsif ($mainsym eq 'Scroll_Lock' || $mainsym eq 'Help') {
  3489.         $vector[$coord + 1] = 'Show_Memory';
  3490.         $vector[$coord + 2] = 'Show_Registers';
  3491.         $vector[$coord + 4] = 'Show_State';
  3492.         $vector[$coord + 8] = $mainsym; # or better 'Show_Registers' ?
  3493.     } elsif ($mainsym =~ /^KP_([0-9])$/) {
  3494.         my $num = $1;
  3495.         $vector[$coord + 2] = 'Hex_'. $num;
  3496.         $vector[$coord + 9] = 'Hex_'. $num;
  3497.         $vector[$coord + 8] = 'Ascii_'. $num;
  3498.     } elsif ($mainsym eq 'Num_Lock') {
  3499.         $vector[$coord + 2] = 'Hex_A';
  3500.         $vector[$coord + 9] = 'Hex_A';
  3501.     } elsif ($mainsym eq 'KP_Divide') {
  3502.         $vector[$coord + 2] = 'Hex_B';
  3503.         $vector[$coord + 9] = 'Hex_B';
  3504.     } elsif ($mainsym eq 'KP_Multiply') {
  3505.         $vector[$coord + 2] = 'Hex_C';
  3506.         $vector[$coord + 9] = 'Hex_C';
  3507.     } elsif ($mainsym eq 'KP_Subtract') {
  3508.         $vector[$coord + 2] = 'Hex_D';
  3509.         $vector[$coord + 9] = 'Hex_D';
  3510.     } elsif ($mainsym eq 'KP_Add') {
  3511.         $vector[$coord + 2] = 'Hex_E';
  3512.         $vector[$coord + 9] = 'Hex_E';
  3513.     } elsif ($mainsym eq 'KP_Enter') {
  3514.         $vector[$coord + 2] = 'Hex_F';
  3515.         $vector[$coord + 9] = 'Hex_F';
  3516.     } elsif ($mainsym eq 'Prior' || $mainsym eq 'PageUp') {
  3517.         $vector[$coord + 1] = 'Scroll_Backward';
  3518.     } elsif ($mainsym eq 'Next' || $mainsym eq 'PageDown') {
  3519.         $vector[$coord + 1] = 'Scroll_Forward';
  3520.     } elsif ($mainsym eq 'Left') {
  3521.         $vector[$coord + 8] = 'Decr_Console';
  3522.     } elsif ($mainsym eq 'Right') {
  3523.         $vector[$coord + 8] = 'Incr_Console';
  3524.     }
  3525.     }
  3526.     return @vector;
  3527. }
  3528.  
  3529. sub print_vector {
  3530.     my $kernel_code = $_[0];
  3531.     my $no_NoSymbol = 1;
  3532.     for my $mask (0 .. 63) {
  3533.     if ($vector[$mask] eq 'NoSymbol') {
  3534.         $no_NoSymbol = 0;
  3535.         last;
  3536.     }
  3537.     }
  3538.     if ($compact) {
  3539.     my $line = ($symbols =~ /:2/ # true if the keymap is non-latin
  3540.             ? "@vector[0, 1, 16, 17, 4, 20, 8, 24, 12, 28]"
  3541.             : "@vector[0, 1, 2, 3, 4, 6, 8, 10, 12, 14]");
  3542.     $line =~ s/NoSymbol/VoidSymbol/g;
  3543.     print "keycode $kernel_code = $line\n";
  3544.     } elsif ($no_NoSymbol) {
  3545.     print "keycode $kernel_code = @vector\n";
  3546.     } else {
  3547.     for my $mask (0 .. 63) {
  3548.         if ($vector[$mask] ne 'NoSymbol') {
  3549.         print "$modifier_combinations[$mask] keycode $kernel_code"
  3550.             ." = $vector[$mask]\n";
  3551.         }
  3552.     }
  3553.     }
  3554. }
  3555.  
  3556. my %at_scancodes = (
  3557.     9 => 1,
  3558.     10 => 2,
  3559.     11 => 3,
  3560.     12 => 4,
  3561.     13 => 5,
  3562.     14 => 6,
  3563.     15 => 7,
  3564.     16 => 8,
  3565.     17 => 9,
  3566.     18 => 10,
  3567.     19 => 11,
  3568.     20 => 12,
  3569.     21 => 13,
  3570.     22 => 14,
  3571.     23 => 15,
  3572.     24 => 16,
  3573.     25 => 17,
  3574.     26 => 18,
  3575.     27 => 19,
  3576.     28 => 20,
  3577.     29 => 21,
  3578.     30 => 22,
  3579.     31 => 23,
  3580.     32 => 24,
  3581.     33 => 25,
  3582.     34 => 26,
  3583.     35 => 27,
  3584.     36 => 28,
  3585.     37 => 29,
  3586.     38 => 30,
  3587.     39 => 31,
  3588.     40 => 32,
  3589.     41 => 33,
  3590.     42 => 34,
  3591.     43 => 35,
  3592.     44 => 36,
  3593.     45 => 37,
  3594.     46 => 38,
  3595.     47 => 39,
  3596.     48 => 40,
  3597.     49 => 41,
  3598.     50 => 42,
  3599.     51 => 43,
  3600.     52 => 44,
  3601.     53 => 45,
  3602.     54 => 46,
  3603.     55 => 47,
  3604.     56 => 48,
  3605.     57 => 49,
  3606.     58 => 50,
  3607.     59 => 51,
  3608.     60 => 52,
  3609.     61 => 53,
  3610.     62 => 54,
  3611.     63 => 55,
  3612.     64 => 56,
  3613.     65 => 57,
  3614.     66 => 58,
  3615.     67 => 59,
  3616.     68 => 60,
  3617.     69 => 61,
  3618.     70 => 62,
  3619.     71 => 63,
  3620.     72 => 64,
  3621.     73 => 65,
  3622.     74 => 66,
  3623.     75 => 67,
  3624.     76 => 68,
  3625.     77 => 69,
  3626.     78 => 70,
  3627.     79 => 71,
  3628.     80 => 72,
  3629.     81 => 73,
  3630.     82 => 74,
  3631.     83 => 75,
  3632.     84 => 76,
  3633.     85 => 77,
  3634.     86 => 78,
  3635.     87 => 79,
  3636.     88 => 80,
  3637.     89 => 81,
  3638.     90 => 82,
  3639.     91 => 83,
  3640.     92 => 84,
  3641.     93 => -1, # fake key (KP_Equal)
  3642.     94 => 86,
  3643.     95 => 87,
  3644.     96 => 88,
  3645.     97 => 102,
  3646.     98 => 103,
  3647.     99 => 104,
  3648.     100 => 105,
  3649.     102 => 106,
  3650.     103 => 107,
  3651.     104 => 108,
  3652.     105 => 109,
  3653.     106 => 110,
  3654.     107 => 111,
  3655.     108 => 96,
  3656.     109 => 97,
  3657.     110 => 119,
  3658.     111 => 99,
  3659.     112 => 98,
  3660.     113 => 100,
  3661.     114 => 101,
  3662.     115 => 125,
  3663.     116 => 126,
  3664.     117 => 127,
  3665.     118 => -1,  # Japanese
  3666.     119 => -1,  # Japanese
  3667.     120 => -1,  # Japanese
  3668.     123 => -1,
  3669.     124 => -1,  # fake key
  3670.     125 => -1,  # fake key
  3671.     126 => -1,  # fake key
  3672.     127 => -1,  # fake key
  3673.     128 => -1,  # fake key
  3674.     129 => -1,  # Japanese
  3675.     131 => -1,  # Japanese
  3676.     133 => 124, # Japanese
  3677.     134 => 121, # Brasilian ABNT2
  3678.     144 => -1,  # Japanese
  3679.     156 => -1,  # fake key
  3680.     208 => -1,  # Japanese
  3681.     209 => -1,  # Korean
  3682.     210 => -1,  # Korean
  3683.     211 => 89,  # Brasilian ABNT2
  3684.     214 => -1,  # alternate between internal and multimedia display
  3685.     215 => -1,  # turn light on/of
  3686.     216 => -1,  # brightness down
  3687.     217 => -1,  # brightness up
  3688. );
  3689.  
  3690. if ($compact) {
  3691.     print "keymaps 0-4,6,8,10,12,14\n";
  3692. } else {
  3693.     print "keymaps 0-63\n";
  3694. }
  3695. if ($arch eq 'at') {
  3696.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  3697.     my $kernel_code = $at_scancodes{$key};
  3698.     if (! defined $kernel_code) {
  3699.         warning "Undefined kernel key code for $key\n";
  3700.         next;
  3701.     }
  3702.     next if ($kernel_code < 0);
  3703.      if ($kernel_code == 84) {
  3704.          @vector = ('Last_Console') x 64;
  3705.      } elsif ($kernel_code == 99) {
  3706.          @vector = ('Control_backslash') x 64;
  3707.      } elsif ($kernel_code == 101) {
  3708.          @vector = ('Break') x 64;
  3709.      } elsif ($kernel_code == 119) {
  3710.          @vector = ('Pause') x 64;
  3711.      } else {
  3712.          @vector = flatten ($key);
  3713.      }
  3714.     if ($kernel_code == 83 || $kernel_code == 111) {
  3715.         for my $coord (0, 16, 32, 48) {
  3716.         $vector[$coord + 6] = 'Boot';
  3717.         $vector[$coord + 12] = 'Boot';
  3718.         $vector[$coord + 14] = 'Boot';
  3719.         }
  3720.     }
  3721.     print_vector $kernel_code;
  3722.     }
  3723. } elsif ($arch eq 'macintosh') {
  3724.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  3725.     my $kernel_code = $key - 8;
  3726.     @vector = flatten ($key);
  3727.     print_vector $kernel_code;
  3728.     }
  3729.     print <<EOT
  3730. keycode 127 =
  3731.         shift   control keycode 127 = Boot
  3732. EOT
  3733. } elsif ($arch eq 'ataritt') {
  3734.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  3735.     my $kernel_code = $key - 8;
  3736.     if ($kernel_code == 97) {
  3737.         @vector = ('F246', 'Break', 'F246', 'F246',
  3738.                'F246', 'F246', 'F246', 'F246', 
  3739.                'Last_Console', 'F246', 'F246', 'F246', 
  3740.                'F246', 'F246', 'F246', 'F246') x 4;
  3741.     } else {
  3742.         @vector = flatten ($key);
  3743.     }
  3744.     if ($kernel_code == 83 || $kernel_code == 113) {
  3745.         for my $coord (0, 16, 32, 48) {
  3746.         $vector[$coord + 6] = 'Boot';
  3747.         $vector[$coord + 12] = 'Boot';
  3748.         $vector[$coord + 14] = 'Boot';
  3749.         }
  3750.     }
  3751.     print_vector $kernel_code;
  3752.     }
  3753. } elsif ($arch eq 'amiga') {
  3754.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  3755.     my $kernel_code = $key - 8;
  3756.     @vector = flatten ($key);
  3757.     if ($kernel_code == 60) {
  3758.         for my $coord (0, 16, 32, 48) {
  3759.         $vector[$coord + 6] = 'Boot';
  3760.         $vector[$coord + 12] = 'Boot';
  3761.         $vector[$coord + 14] = 'Boot';
  3762.         }
  3763.     }
  3764.     print_vector $kernel_code;
  3765.     }
  3766. } elsif ($arch eq 'sun') {
  3767.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  3768.     my $kernel_code = $key - 7;
  3769.     @vector = flatten ($key);
  3770.     if ($kernel_code == 50) {
  3771.         for my $coord (0, 16, 32, 48) {
  3772.         $vector[$coord + 6] = 'Boot';
  3773.         $vector[$coord + 12] = 'Boot';
  3774.         $vector[$coord + 14] = 'Boot';
  3775.         }
  3776.     }
  3777.     print_vector $kernel_code;
  3778.     }
  3779. } else {
  3780.     die "$0: Unsupported keyboard type $arch\n";
  3781. }
  3782.  
  3783. print "strings as usual\n";
  3784.  
  3785. if ($charmap && -f "/etc/console-setup/compose.${charmap}.inc") {
  3786.     system("cat /etc/console-setup/compose.${charmap}.inc");
  3787. }
  3788.  
  3789. exit 0;
  3790.